Merge remote-tracking branches 'asoc/topic/rt5514', 'asoc/topic/rt5616', 'asoc/topic...
authorMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:53:14 +0000 (15:53 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 12 Dec 2016 15:53:14 +0000 (15:53 +0000)
2011 files changed:
CREDITS
Documentation/ABI/testing/sysfs-class-cxl
Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
Documentation/ABI/testing/sysfs-platform-sst-atom [new file with mode: 0644]
Documentation/device-mapper/dm-raid.txt
Documentation/devicetree/bindings/clock/uniphier-clock.txt
Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ipmi/ipmi-smic.txt [moved from Documentation/devicetree/bindings/ipmi.txt with 100% similarity]
Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
Documentation/devicetree/bindings/net/ethernet.txt
Documentation/devicetree/bindings/net/marvell-orion-net.txt
Documentation/devicetree/bindings/pci/rockchip-pcie.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
Documentation/devicetree/bindings/reset/uniphier-reset.txt
Documentation/devicetree/bindings/serial/cdns,uart.txt
Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
Documentation/devicetree/bindings/sound/axentia,tse850-pcm5142.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs35l34.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs42l42.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/davinci-mcbsp.txt
Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5514.txt
Documentation/devicetree/bindings/sound/rt5665.txt [new file with mode: 0755]
Documentation/devicetree/bindings/timer/jcore,pit.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/dwc2.txt
Documentation/filesystems/Locking
Documentation/filesystems/proc.txt
Documentation/filesystems/vfs.txt
Documentation/gpio/board.txt
Documentation/i2c/i2c-topology
Documentation/networking/dsa/dsa.txt
Documentation/networking/netdev-FAQ.txt
Documentation/networking/nf_conntrack-sysctl.txt
Documentation/sound/alsa/soc/codec_to_codec.txt [new file with mode: 0644]
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/locking.txt
MAINTAINERS
Makefile
arch/alpha/kernel/ptrace.c
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/boot/Makefile
arch/arc/boot/dts/axc001.dtsi
arch/arc/boot/dts/nsim_700.dts
arch/arc/boot/dts/nsimosci.dts
arch/arc/configs/nsim_700_defconfig
arch/arc/configs/nsim_hs_defconfig
arch/arc/configs/nsim_hs_smp_defconfig
arch/arc/configs/nsimosci_defconfig
arch/arc/configs/nsimosci_hs_defconfig
arch/arc/configs/nsimosci_hs_smp_defconfig
arch/arc/include/asm/arcregs.h
arch/arc/include/asm/cache.h
arch/arc/include/asm/delay.h
arch/arc/include/asm/elf.h
arch/arc/include/asm/mcip.h
arch/arc/include/asm/module.h
arch/arc/include/asm/pgtable.h
arch/arc/include/asm/setup.h
arch/arc/include/asm/smp.h
arch/arc/include/asm/syscalls.h
arch/arc/include/uapi/asm/unistd.h
arch/arc/kernel/devtree.c
arch/arc/kernel/mcip.c
arch/arc/kernel/module.c
arch/arc/kernel/process.c
arch/arc/kernel/setup.c
arch/arc/kernel/smp.c
arch/arc/kernel/time.c
arch/arc/kernel/troubleshoot.c
arch/arc/mm/cache.c
arch/arc/mm/dma.c
arch/arc/mm/tlb.c
arch/arc/mm/tlbex.S
arch/arc/plat-eznps/smp.c
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/imx53-qsb.dts
arch/arm/boot/dts/imx7s.dtsi
arch/arm/boot/dts/logicpd-som-lv.dtsi
arch/arm/boot/dts/logicpd-torpedo-som.dtsi
arch/arm/boot/dts/omap5-board-common.dtsi
arch/arm/boot/dts/orion5x-linkstation-lsgl.dts
arch/arm/boot/dts/ste-snowball.dts
arch/arm/boot/dts/stih407-family.dtsi
arch/arm/boot/dts/stih410-b2260.dts
arch/arm/boot/dts/sun5i-gr8-evb.dts [moved from arch/arm/boot/dts/ntc-gr8-evb.dts with 99% similarity]
arch/arm/boot/dts/sun5i-gr8.dtsi [moved from arch/arm/boot/dts/ntc-gr8.dtsi with 100% similarity]
arch/arm/boot/dts/sun8i-a23-a33.dtsi
arch/arm/boot/dts/sun8i-h3.dtsi
arch/arm/boot/dts/uniphier-pro5.dtsi
arch/arm/boot/dts/uniphier-pxs2.dtsi
arch/arm/boot/dts/vf500.dtsi
arch/arm/configs/multi_v7_defconfig
arch/arm/include/asm/Kbuild
arch/arm/include/asm/kvm_asm.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/kvm_hyp.h
arch/arm/include/asm/unistd.h
arch/arm/include/uapi/asm/unistd.h
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c [new file with mode: 0644]
arch/arm/kernel/calls.S
arch/arm/kernel/entry-ftrace.S
arch/arm/kernel/head.S
arch/arm/kernel/smccc-call.S
arch/arm/kernel/traps.c
arch/arm/kernel/vmlinux-xip.lds.S
arch/arm/kvm/arm.c
arch/arm/kvm/hyp/tlb.c
arch/arm/lib/ashldi3.S
arch/arm/lib/ashrdi3.S
arch/arm/lib/backtrace.S
arch/arm/lib/bitops.h
arch/arm/lib/bswapsdi2.S
arch/arm/lib/clear_user.S
arch/arm/lib/copy_from_user.S
arch/arm/lib/copy_page.S
arch/arm/lib/copy_to_user.S
arch/arm/lib/csumipv6.S
arch/arm/lib/csumpartial.S
arch/arm/lib/csumpartialcopy.S
arch/arm/lib/csumpartialcopygeneric.S
arch/arm/lib/csumpartialcopyuser.S
arch/arm/lib/delay.c
arch/arm/lib/div64.S
arch/arm/lib/findbit.S
arch/arm/lib/getuser.S
arch/arm/lib/io-readsb.S
arch/arm/lib/io-readsl.S
arch/arm/lib/io-readsw-armv3.S
arch/arm/lib/io-readsw-armv4.S
arch/arm/lib/io-writesb.S
arch/arm/lib/io-writesl.S
arch/arm/lib/io-writesw-armv3.S
arch/arm/lib/io-writesw-armv4.S
arch/arm/lib/lib1funcs.S
arch/arm/lib/lshrdi3.S
arch/arm/lib/memchr.S
arch/arm/lib/memcpy.S
arch/arm/lib/memmove.S
arch/arm/lib/memset.S
arch/arm/lib/memzero.S
arch/arm/lib/muldi3.S
arch/arm/lib/putuser.S
arch/arm/lib/strchr.S
arch/arm/lib/strrchr.S
arch/arm/lib/uaccess_with_memcpy.c
arch/arm/lib/ucmpdi2.S
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/gpc.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/ssi-fiq-ksym.c [new file with mode: 0644]
arch/arm/mach-imx/ssi-fiq.S
arch/arm/mach-mvebu/Kconfig
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/prm3xxx.c
arch/arm/mach-omap2/voltage.c
arch/arm/mach-uniphier/Kconfig
arch/arm/mm/abort-lv4t.S
arch/arm/mm/dma-mapping.c
arch/arm/mm/proc-v7m.S
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/Makefile
arch/arm64/boot/dts/arm/juno-base.dtsi
arch/arm64/boot/dts/arm/juno-r1.dts
arch/arm64/boot/dts/arm/juno-r2.dts
arch/arm64/boot/dts/arm/juno.dts
arch/arm64/boot/dts/broadcom/ns2-svk.dts
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
arch/arm64/boot/dts/marvell/armada-37xx.dtsi
arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts
arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
arch/arm64/include/asm/alternative.h
arch/arm64/include/asm/cpucaps.h [new file with mode: 0644]
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/exec.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/lse.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/module.h
arch/arm64/include/asm/percpu.h
arch/arm64/include/asm/perf_event.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/uaccess.h
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/head.S
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/process.c
arch/arm64/kernel/sleep.S
arch/arm64/kernel/smp.c
arch/arm64/kernel/suspend.c
arch/arm64/kernel/traps.c
arch/arm64/kvm/hyp/tlb.c
arch/arm64/kvm/sys_regs.c
arch/arm64/mm/fault.c
arch/arm64/mm/init.c
arch/arm64/mm/numa.c
arch/blackfin/kernel/ptrace.c
arch/cris/arch-v32/drivers/cryptocop.c
arch/cris/arch-v32/kernel/ptrace.c
arch/h8300/include/asm/thread_info.h
arch/h8300/kernel/signal.c
arch/ia64/kernel/err_inject.c
arch/ia64/kernel/ptrace.c
arch/m32r/kernel/ptrace.c
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/include/asm/delay.h
arch/mips/Makefile
arch/mips/boot/dts/mti/malta.dts
arch/mips/generic/init.c
arch/mips/include/asm/fpu_emulator.h
arch/mips/include/asm/kvm_host.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/switch_to.h
arch/mips/include/asm/tlb.h
arch/mips/kernel/mips-cpc.c
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/ptrace32.c
arch/mips/kernel/r2300_fpu.S
arch/mips/kernel/r6000_fpu.S
arch/mips/kernel/relocate.c
arch/mips/kernel/setup.c
arch/mips/kernel/time.c
arch/mips/kernel/traps.c
arch/mips/kvm/emulate.c
arch/mips/kvm/mips.c
arch/mips/kvm/mmu.c
arch/mips/lantiq/falcon/sysctrl.c
arch/mips/lib/dump_tlb.c
arch/mips/lib/r3k_dump_tlb.c
arch/mips/mm/fault.c
arch/mips/mm/gup.c
arch/mips/mm/init.c
arch/mips/mm/tlb-r4k.c
arch/nios2/kernel/time.c
arch/openrisc/include/asm/cache.h
arch/parisc/Kconfig
arch/parisc/include/asm/pgtable.h
arch/parisc/include/uapi/asm/unistd.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/drivers.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/pacache.S
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/setup.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/time.c
arch/powerpc/boot/Makefile
arch/powerpc/boot/main.c
arch/powerpc/boot/opal-calls.S
arch/powerpc/boot/opal.c
arch/powerpc/boot/ops.h
arch/powerpc/include/asm/asm-prototypes.h
arch/powerpc/include/asm/checksum.h
arch/powerpc/include/asm/cpuidle.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/tlb.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/cpu_setup_power.S
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/idle_book3s.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/ptrace32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/kvm/book3s_hv_rm_xics.c
arch/powerpc/mm/copro_fault.c
arch/powerpc/mm/hash64_4k.c
arch/powerpc/mm/hash64_64k.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable-radix.c
arch/powerpc/mm/tlb-radix.c
arch/s390/hypfs/hypfs_diag.c
arch/s390/include/asm/ftrace.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/dis.c
arch/s390/kernel/dumpstack.c
arch/s390/kernel/perf_event.c
arch/s390/kernel/stacktrace.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kvm/intercept.c
arch/s390/kvm/sthyi.c
arch/s390/mm/gup.c
arch/s390/mm/hugetlbpage.c
arch/s390/mm/init.c
arch/s390/oprofile/init.c
arch/s390/pci/pci_dma.c
arch/score/kernel/ptrace.c
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/configs/j2_defconfig
arch/sh/mm/gup.c
arch/sparc/Kconfig
arch/sparc/include/asm/cpudata_64.h
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/iommu_64.h
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/include/asm/topology_64.h
arch/sparc/include/asm/uaccess_64.h
arch/sparc/kernel/head_64.S
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/iommu.c
arch/sparc/kernel/iommu_common.h
arch/sparc/kernel/jump_label.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/pci_sun4v.h
arch/sparc/kernel/pci_sun4v_asm.S
arch/sparc/kernel/ptrace_64.c
arch/sparc/kernel/signal_32.c
arch/sparc/kernel/smp_64.c
arch/sparc/lib/GENcopy_from_user.S
arch/sparc/lib/GENcopy_to_user.S
arch/sparc/lib/GENmemcpy.S
arch/sparc/lib/Makefile
arch/sparc/lib/NG2copy_from_user.S
arch/sparc/lib/NG2copy_to_user.S
arch/sparc/lib/NG2memcpy.S
arch/sparc/lib/NG4copy_from_user.S
arch/sparc/lib/NG4copy_to_user.S
arch/sparc/lib/NG4memcpy.S
arch/sparc/lib/NGcopy_from_user.S
arch/sparc/lib/NGcopy_to_user.S
arch/sparc/lib/NGmemcpy.S
arch/sparc/lib/U1copy_from_user.S
arch/sparc/lib/U1copy_to_user.S
arch/sparc/lib/U1memcpy.S
arch/sparc/lib/U3copy_from_user.S
arch/sparc/lib/U3copy_to_user.S
arch/sparc/lib/U3memcpy.S
arch/sparc/lib/copy_in_user.S
arch/sparc/lib/user_fixup.c [deleted file]
arch/sparc/mm/gup.c
arch/sparc/mm/init_64.c
arch/sparc/mm/tsb.c
arch/sparc/mm/ultra.S
arch/tile/include/asm/cache.h
arch/tile/kernel/time.c
arch/x86/boot/compressed/Makefile
arch/x86/boot/cpu.c
arch/x86/crypto/aesni-intel_glue.c
arch/x86/entry/Makefile
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
arch/x86/events/amd/core.c
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/cstate.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/rapl.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore_snb.c
arch/x86/events/perf_event.h
arch/x86/include/asm/compat.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/intel-mid.h
arch/x86/include/asm/io.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/rwsem.h
arch/x86/include/asm/thread_info.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/microcode/amd.c
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/cpu/vmware.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/e820.c
arch/x86/kernel/fpu/core.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/head_32.S
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/mcount_64.S
arch/x86/kernel/quirks.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal_compat.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/step.c
arch/x86/kernel/sysfb_simplefb.c
arch/x86/kernel/unwind_guess.c
arch/x86/kvm/emulate.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/ioapic.h
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/extable.c
arch/x86/mm/gup.c
arch/x86/mm/kaslr.c
arch/x86/mm/mpx.c
arch/x86/mm/pat.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/intel-mid/device_libs/Makefile
arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c [moved from arch/x86/platform/intel-mid/device_libs/platform_wdt.c with 65% similarity]
arch/x86/platform/intel-mid/pwr.c
arch/x86/platform/olpc/olpc-xo15-sci.c
arch/x86/platform/uv/bios_uv.c
arch/x86/purgatory/Makefile
arch/x86/tools/relocs.h
arch/x86/um/ptrace_32.c
arch/x86/um/ptrace_64.c
arch/x86/xen/enlighten.c
arch/xtensa/include/uapi/asm/unistd.h
arch/xtensa/kernel/time.c
arch/xtensa/kernel/traps.c
block/badblocks.c
block/blk-flush.c
block/blk-map.c
block/blk-mq.c
crypto/Makefile
crypto/algif_aead.c
crypto/algif_hash.c
crypto/asymmetric_keys/x509_cert_parser.c
crypto/drbg.c
crypto/mcryptd.c
crypto/scatterwalk.c
drivers/Makefile
drivers/acpi/acpi_apd.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_platform.c
drivers/acpi/acpica/dsinit.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dswload2.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/nsload.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/apei/ghes.c
drivers/acpi/dptf/int340x_thermal.c
drivers/acpi/nfit/core.c
drivers/acpi/nfit/nfit.h
drivers/acpi/pci_link.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/android/binder.c
drivers/ata/ahci.c
drivers/ata/libata-scsi.c
drivers/ata/sata_mv.c
drivers/atm/eni.c
drivers/atm/lanai.c
drivers/base/Kconfig
drivers/base/dd.c
drivers/base/power/main.c
drivers/block/DAC960.c
drivers/block/aoe/aoecmd.c
drivers/block/drbd/drbd_main.c
drivers/block/nbd.c
drivers/block/rbd.c
drivers/block/virtio_blk.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/btwilink.c
drivers/bluetooth/hci_bcm.c
drivers/bus/Kconfig
drivers/char/hw_random/core.c
drivers/char/ipmi/Kconfig
drivers/char/ipmi/Makefile
drivers/char/ipmi/bt-bmc.c [new file with mode: 0644]
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ppdev.c
drivers/char/tpm/tpm-interface.c
drivers/char/virtio_console.c
drivers/clk/at91/clk-programmable.c
drivers/clk/bcm/Kconfig
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/berlin/bg2.c
drivers/clk/berlin/bg2q.c
drivers/clk/clk-efm32gg.c
drivers/clk/clk-max77686.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-xgene.c
drivers/clk/hisilicon/clk-hi6220.c
drivers/clk/imx/clk-pllv3.c
drivers/clk/mediatek/Kconfig
drivers/clk/mmp/clk-of-mmp2.c
drivers/clk/mmp/clk-of-pxa168.c
drivers/clk/mmp/clk-of-pxa910.c
drivers/clk/mvebu/armada-37xx-periph.c
drivers/clk/rockchip/clk-ddr.c
drivers/clk/samsung/clk-exynos-audss.c
drivers/clk/samsung/clk-exynos-clkout.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/sunxi-ng/ccu-sun8i-a33.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/uniphier/clk-uniphier-core.c
drivers/clk/uniphier/clk-uniphier-mio.c
drivers/clk/uniphier/clk-uniphier-mux.c
drivers/clk/uniphier/clk-uniphier.h
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/jcore-pit.c [new file with mode: 0644]
drivers/clocksource/timer-sun5i.c
drivers/cpufreq/intel_pstate.c
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/ctrl.c
drivers/crypto/chelsio/chcr_algo.h
drivers/crypto/marvell/hash.c
drivers/dax/Kconfig
drivers/dax/dax.c
drivers/dax/pmem.c
drivers/dma/Kconfig
drivers/dma/cppi41.c
drivers/dma/edma.c
drivers/dma/sun6i-dma.c
drivers/extcon/extcon-arizona.c
drivers/extcon/extcon-qcom-spmi-misc.c
drivers/firewire/net.c
drivers/firewire/nosy.c
drivers/firmware/efi/libstub/Makefile
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-ath79.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-mxs.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-tc3589x.c
drivers/gpio/gpio-ts4800.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
drivers/gpu/drm/amd/amdgpu/cz_dpm.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/kv_dpm.c
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
drivers/gpu/drm/amd/amdgpu/si_dpm.c
drivers/gpu/drm/amd/amdgpu/tonga_ih.c
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/include/amd_shared.h
drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c
drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c
drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_thermal.c
drivers/gpu/drm/amd/powerplay/smumgr/iceland_smc.c
drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smc.c
drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
drivers/gpu/drm/amd/scheduler/sched_fence.c
drivers/gpu/drm/arc/arcpgu_hdmi.c
drivers/gpu/drm/arm/hdlcd_crtc.c
drivers/gpu/drm/arm/hdlcd_drv.c
drivers/gpu/drm/armada/armada_crtc.c
drivers/gpu/drm/ast/ast_ttm.c
drivers/gpu/drm/cirrus/cirrus_ttm.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/etnaviv/etnaviv_buffer.c
drivers/gpu/drm/etnaviv/etnaviv_gem.c
drivers/gpu/drm/etnaviv/etnaviv_mmu.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_fence.c
drivers/gpu/drm/i915/i915_gem_userptr.c
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_device_info.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_vbt_defs.h
drivers/gpu/drm/imx/imx-drm-core.c
drivers/gpu/drm/imx/ipuv3-crtc.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/mediatek/mtk_disp_ovl.c
drivers/gpu/drm/mediatek/mtk_dpi.c
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
drivers/gpu/drm/mediatek/mtk_dsi.c
drivers/gpu/drm/mediatek/mtk_hdmi.c
drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/msm/dsi/dsi_host.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c
drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gem_shrinker.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_dp_auxch.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/sti/sti_drv.c
drivers/gpu/drm/sun4i/sun4i_drv.c
drivers/gpu/drm/sun4i/sun4i_rgb.c
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/via/via_dmablit.c
drivers/gpu/drm/virtio/virtgpu_display.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/gpu/ipu-v3/ipu-image-convert.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-dr.c
drivers/hid/hid-ids.h
drivers/hid/hid-led.c
drivers/hid/hid-lg.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-rmi.c
drivers/hid/hid-sensor-custom.c
drivers/hid/hid-sensor-hub.c
drivers/hid/intel-ish-hid/ipc/ipc.c
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/usbhid/hid-quirks.c
drivers/hv/hv_util.c
drivers/hv/vmbus_drv.c
drivers/hwmon/adm9240.c
drivers/hwmon/hwmon.c
drivers/hwmon/max31790.c
drivers/i2c/Kconfig
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-digicolor.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-jz4780.c
drivers/i2c/busses/i2c-octeon-core.c
drivers/i2c/busses/i2c-octeon-core.h
drivers/i2c/busses/i2c-rk3x.c
drivers/i2c/busses/i2c-xgene-slimpro.c
drivers/i2c/busses/i2c-xlp9xx.c
drivers/i2c/busses/i2c-xlr.c
drivers/i2c/i2c-core.c
drivers/i2c/muxes/Kconfig
drivers/i2c/muxes/i2c-demux-pinctrl.c
drivers/i2c/muxes/i2c-mux-pca954x.c
drivers/iio/accel/st_accel_core.c
drivers/iio/adc/Kconfig
drivers/iio/chemical/atlas-ph-sensor.c
drivers/iio/common/hid-sensors/hid-sensor-attributes.c
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/orientation/hid-sensor-rotation.c
drivers/iio/temperature/maxim_thermocouple.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/umem.c
drivers/infiniband/core/umem_odp.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/hfi1/affinity.c
drivers/infiniband/hw/hfi1/affinity.h
drivers/infiniband/hw/hfi1/chip.c
drivers/infiniband/hw/hfi1/chip.h
drivers/infiniband/hw/hfi1/driver.c
drivers/infiniband/hw/hfi1/file_ops.c
drivers/infiniband/hw/hfi1/hfi.h
drivers/infiniband/hw/hfi1/init.c
drivers/infiniband/hw/hfi1/pcie.c
drivers/infiniband/hw/hfi1/pio.c
drivers/infiniband/hw/hfi1/rc.c
drivers/infiniband/hw/hfi1/sdma.c
drivers/infiniband/hw/hfi1/sysfs.c
drivers/infiniband/hw/hfi1/trace_rx.h
drivers/infiniband/hw/hfi1/user_sdma.c
drivers/infiniband/hw/mlx4/ah.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx5/cq.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/qedr/Kconfig
drivers/infiniband/hw/qib/qib_user_pages.c
drivers/infiniband/hw/usnic/usnic_uiom.c
drivers/infiniband/sw/rdmavt/dma.c
drivers/infiniband/sw/rxe/rxe_net.c
drivers/infiniband/sw/rxe/rxe_qp.c
drivers/infiniband/sw/rxe/rxe_queue.c
drivers/infiniband/sw/rxe/rxe_queue.h
drivers/infiniband/sw/rxe/rxe_req.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/input/misc/arizona-haptics.c
drivers/input/mouse/focaltech.c
drivers/input/mouse/psmouse-base.c
drivers/input/serio/i8042-x86ia64io.h
drivers/iommu/arm-smmu-v3.c
drivers/iommu/arm-smmu.c
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel-svm.c
drivers/ipack/ipack.c
drivers/irqchip/Kconfig
drivers/irqchip/irq-eznps.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-jcore-aic.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/hisax/hfc4s8s_l1.c
drivers/mailbox/pcc.c
drivers/md/dm-raid.c
drivers/md/dm-raid1.c
drivers/md/dm-rq.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/md.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5-cache.c
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/gp8psk-fe.c [moved from drivers/media/usb/dvb-usb/gp8psk-fe.c with 69% similarity]
drivers/media/dvb-frontends/gp8psk-fe.h [new file with mode: 0644]
drivers/media/i2c/ir-kbd-i2c.c
drivers/media/pci/ivtv/ivtv-udma.c
drivers/media/pci/ivtv/ivtv-yuv.c
drivers/media/platform/omap/omap_vout.c
drivers/media/tuners/tuner-xc2028.c
drivers/media/usb/b2c2/flexcop-usb.c
drivers/media/usb/b2c2/flexcop-usb.h
drivers/media/usb/cpia2/cpia2_usb.c
drivers/media/usb/dvb-usb/Makefile
drivers/media/usb/dvb-usb/af9005.c
drivers/media/usb/dvb-usb/cinergyT2-core.c
drivers/media/usb/dvb-usb/cinergyT2-fe.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/cxusb.h
drivers/media/usb/dvb-usb/dib0700_core.c
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/dibusb-common.c
drivers/media/usb/dvb-usb/dibusb.h
drivers/media/usb/dvb-usb/digitv.c
drivers/media/usb/dvb-usb/digitv.h
drivers/media/usb/dvb-usb/dtt200u-fe.c
drivers/media/usb/dvb-usb/dtt200u.c
drivers/media/usb/dvb-usb/dtv5100.c
drivers/media/usb/dvb-usb/dvb-usb-init.c
drivers/media/usb/dvb-usb/dvb-usb.h
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/dvb-usb/gp8psk.c
drivers/media/usb/dvb-usb/gp8psk.h
drivers/media/usb/dvb-usb/nova-t-usb2.c
drivers/media/usb/dvb-usb/pctv452e.c
drivers/media/usb/dvb-usb/technisat-usb2.c
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/stkwebcam/stk-webcam.c
drivers/media/v4l2-core/videobuf-dma-sg.c
drivers/media/v4l2-core/videobuf2-memops.c
drivers/memstick/host/rtsx_usb_ms.c
drivers/mfd/intel-lpss-pci.c
drivers/mfd/intel-lpss.c
drivers/mfd/intel_soc_pmic_bxtwc.c
drivers/mfd/mfd-core.c
drivers/mfd/stmpe.c
drivers/mfd/syscon.c
drivers/mfd/wm8994-core.c
drivers/misc/cxl/api.c
drivers/misc/cxl/context.c
drivers/misc/cxl/cxl.h
drivers/misc/cxl/file.c
drivers/misc/cxl/guest.c
drivers/misc/cxl/main.c
drivers/misc/cxl/pci.c
drivers/misc/cxl/sysfs.c
drivers/misc/genwqe/card_utils.c
drivers/misc/mei/bus-fixup.c
drivers/misc/mei/hw-txe.c
drivers/misc/mic/scif/scif_rma.c
drivers/misc/sgi-gru/grufault.c
drivers/misc/sgi-gru/grumain.c
drivers/misc/vmw_vmci/vmci_doorbell.c
drivers/misc/vmw_vmci/vmci_driver.c
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.h
drivers/mmc/core/mmc.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/rtsx_usb_sdmmc.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/mtk_ecc.c
drivers/mtd/nand/nand_base.c
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/fastmap.c
drivers/net/can/sja1000/plx_pci.c
drivers/net/can/usb/peak_usb/pcan_ucan.h
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/can/usb/peak_usb/pcan_usb_core.h
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/b53/b53_mmap.c
drivers/net/dsa/bcm_sf2.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/aurora/nb8800.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nic_main.c
drivers/net/ethernet/cavium/thunder/nic_reg.h
drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.h
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/cavium/thunder/thunder_bgx.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
drivers/net/ethernet/chelsio/cxgb4/sched.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/cirrus/ep93xx_eth.c
drivers/net/ethernet/cisco/enic/vnic_rq.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/ezchip/nps_enet.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fman/fman_memac.c
drivers/net/ethernet/freescale/fman/fman_tgec.c
drivers/net/ethernet/freescale/fman/mac.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/hisilicon/hns/hnae.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
drivers/net/ethernet/hisilicon/hns_mdio.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmveth.h
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_clock.c
drivers/net/ethernet/mellanox/mlx4/en_cq.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_port.c
drivers/net/ethernet/mellanox/mlx4/en_selftest.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
drivers/net/ethernet/mellanox/mlx5/core/alloc.c
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlxsw/pci.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/mellanox/mlxsw/switchx2.c
drivers/net/ethernet/qlogic/Kconfig
drivers/net/ethernet/qlogic/qed/Makefile
drivers/net/ethernet/qlogic/qed/qed_cxt.c
drivers/net/ethernet/qlogic/qed/qed_dcbx.c
drivers/net/ethernet/qlogic/qed/qed_debug.c
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_ll2.c
drivers/net/ethernet/qlogic/qed/qed_ll2.h
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_roce.c
drivers/net/ethernet/qlogic/qed/qed_roce.h
drivers/net/ethernet/qlogic/qed/qed_sp.h
drivers/net/ethernet/qlogic/qed/qed_spq.c
drivers/net/ethernet/qlogic/qede/Makefile
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/qualcomm/emac/emac-mac.c
drivers/net/ethernet/qualcomm/emac/emac-phy.c
drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
drivers/net/ethernet/qualcomm/emac/emac.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/rocker/rocker_main.c
drivers/net/ethernet/rocker/rocker_ofdpa.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/Kconfig
drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/descs.h
drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
drivers/net/ethernet/sun/sunbmac.c
drivers/net/ethernet/sun/sunbmac.h
drivers/net/ethernet/sun/sunqe.c
drivers/net/ethernet/sun/sunqe.h
drivers/net/ethernet/synopsys/dwc_eth_qos.c
drivers/net/ethernet/ti/cpmac.c
drivers/net/ethernet/ti/cpsw-phy-sel.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/geneve.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/ieee802154/adf7242.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/irda/irda-usb.c
drivers/net/irda/w83977af_ir.c
drivers/net/macsec.c
drivers/net/macvlan.c
drivers/net/macvtap.c
drivers/net/phy/at803x.c
drivers/net/phy/dp83848.c
drivers/net/phy/fixed_phy.c
drivers/net/phy/micrel.c
drivers/net/phy/phy_device.c
drivers/net/phy/realtek.c
drivers/net/phy/vitesse.c
drivers/net/tun.c
drivers/net/usb/asix_common.c
drivers/net/usb/asix_devices.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/kalmia.c
drivers/net/usb/lan78xx.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vrf.c
drivers/net/vxlan.c
drivers/net/wan/Kconfig
drivers/net/wan/slic_ds26522.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
drivers/net/wireless/realtek/rtlwifi/core.c
drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
drivers/net/wireless/realtek/rtlwifi/wifi.h
drivers/net/wireless/ti/wlcore/sdio.c
drivers/net/xen-netfront.c
drivers/nfc/mei_phy.c
drivers/ntb/hw/intel/ntb_hw_intel.c
drivers/ntb/ntb_transport.c
drivers/ntb/test/ntb_perf.c
drivers/ntb/test/ntb_pingpong.c
drivers/nvdimm/Kconfig
drivers/nvdimm/bus.c
drivers/nvdimm/namespace_devs.c
drivers/nvdimm/pmem.c
drivers/nvme/host/core.c
drivers/nvme/host/lightnvm.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/scsi.c
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/core.c
drivers/nvme/target/discovery.c
drivers/nvme/target/rdma.c
drivers/of/base.c
drivers/of/of_mdio.c
drivers/pci/host/pci-layerscape.c
drivers/pci/host/pcie-designware-plat.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-qcom.c
drivers/pci/host/pcie-rockchip.c
drivers/pci/msi.c
drivers/pci/pci-mid.c
drivers/pci/pcie/aer/aer_inject.c
drivers/pci/probe.c
drivers/pci/setup-res.c
drivers/pcmcia/soc_common.c
drivers/perf/xgene_pmu.c
drivers/phy/phy-da8xx-usb.c
drivers/phy/phy-rockchip-pcie.c
drivers/phy/phy-sun4i-usb.c
drivers/phy/phy-twl4030-usb.c
drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
drivers/pinctrl/aspeed/pinctrl-aspeed.c
drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
drivers/pinctrl/freescale/pinctrl-imx.c
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/platform/goldfish/goldfish_pipe.c
drivers/platform/x86/Kconfig
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel-hid.c
drivers/platform/x86/intel-vbtn.c
drivers/platform/x86/toshiba-wmi.c
drivers/pwm/pwm-meson.c
drivers/pwm/sysfs.c
drivers/rapidio/devices/rio_mport_cdev.c
drivers/regulator/core.c
drivers/regulator/rk808-regulator.c
drivers/reset/reset-uniphier.c
drivers/rtc/rtc-asm9260.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-omap.c
drivers/s390/block/dasd_eckd.c
drivers/s390/cio/chp.c
drivers/s390/scsi/zfcp_dbf.c
drivers/scsi/NCR5380.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/ipr.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libiscsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qlogicpti.h
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_dh.c
drivers/scsi/scsi_scan.c
drivers/scsi/st.c
drivers/scsi/vmw_pvscsi.c
drivers/scsi/vmw_pvscsi.h
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi.c
drivers/staging/android/ion/ion.c
drivers/staging/android/ion/ion_of.c
drivers/staging/comedi/drivers/ni_tio.c
drivers/staging/greybus/arche-platform.c
drivers/staging/greybus/es2.c
drivers/staging/greybus/gpio.c
drivers/staging/greybus/module.c
drivers/staging/greybus/uart.c
drivers/staging/iio/accel/sca3000_core.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/lustre/lustre/llite/lproc_llite.c
drivers/staging/media/bcm2048/radio-bcm2048.c
drivers/staging/nvec/nvec_ps2.c
drivers/staging/sm750fb/ddk750_reg.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
drivers/staging/wilc1000/host_interface.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/target_core_transport.c
drivers/target/target_core_user.c
drivers/target/target_core_xcopy.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_sess.c
drivers/thermal/intel_pch_thermal.c
drivers/thermal/intel_powerclamp.c
drivers/tty/serial/8250/8250_lpss.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/8250_uniphier.c
drivers/tty/serial/Kconfig
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.h
drivers/tty/serial/xilinx_uartps.c
drivers/tty/vt/vt.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/udc.c
drivers/usb/class/cdc-acm.c
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-st.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.h
drivers/usb/musb/da8xx.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/renesas_usbhs/rcar3.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/usb-serial.c
drivers/usb/storage/transport.c
drivers/usb/wusbcore/crypto.c
drivers/uwb/lc-rc.c
drivers/uwb/pal.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/vhost/vsock.c
drivers/video/fbdev/amba-clcd-versatile.c
drivers/video/fbdev/pvr2fb.c
drivers/virt/fsl_hypervisor.c
drivers/virtio/config.c [deleted file]
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_pci_legacy.c
drivers/virtio/virtio_ring.c
drivers/vme/vme.c
drivers/watchdog/Kconfig
drivers/watchdog/wdat_wdt.c
drivers/xen/manage.c
drivers/xen/xenbus/xenbus_dev_frontend.c
drivers/xen/xenbus/xenbus_probe_frontend.c
fs/afs/cmservice.c
fs/afs/fsclient.c
fs/afs/internal.h
fs/afs/rxrpc.c
fs/aio.c
fs/btrfs/compression.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/relocation.c
fs/btrfs/send.c
fs/btrfs/tree-log.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/super.c
fs/ceph/xattr.c
fs/cifs/cifsencrypt.c
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/coredump.c
fs/crypto/crypto.c
fs/crypto/fname.c
fs/crypto/keyinfo.c
fs/crypto/policy.c
fs/exec.c
fs/exofs/dir.c
fs/ext2/inode.c
fs/ext4/block_validity.c
fs/ext4/ext4.h
fs/ext4/mballoc.h
fs/ext4/namei.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/ext4/xattr.c
fs/f2fs/gc.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/iomap.c
fs/isofs/inode.c
fs/isofs/rock.c
fs/jbd2/transaction.c
fs/kernfs/file.c
fs/locks.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/callback.c
fs/nfs/client.c
fs/nfs/namespace.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4session.c
fs/nfs/nfs4state.c
fs/nfs/pnfs.c
fs/nfsd/netns.h
fs/nfsd/nfs4state.c
fs/ntfs/dir.c
fs/ocfs2/dir.c
fs/orangefs/dcache.c
fs/orangefs/file.c
fs/orangefs/namei.c
fs/orangefs/orangefs-debugfs.c
fs/orangefs/orangefs-kernel.h
fs/orangefs/orangefs-mod.c
fs/overlayfs/copy_up.c
fs/overlayfs/inode.c
fs/overlayfs/super.c
fs/proc/array.c
fs/proc/base.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/splice.c
fs/ubifs/dir.c
fs/ubifs/xattr.c
fs/xattr.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap.h
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_defer.c
fs/xfs/libxfs/xfs_dquot_buf.c
fs/xfs/libxfs/xfs_format.h
fs/xfs/libxfs/xfs_inode_buf.c
fs/xfs/libxfs/xfs_inode_buf.h
fs/xfs/xfs_file.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_reflink.c
fs/xfs/xfs_reflink.h
fs/xfs/xfs_sysfs.c
fs/xfs/xfs_trace.h
include/acpi/actbl.h
include/acpi/pcc.h
include/acpi/platform/aclinux.h
include/asm-generic/export.h
include/asm-generic/percpu.h
include/asm-generic/sections.h
include/asm-generic/vmlinux.lds.h
include/crypto/drbg.h
include/drm/drm_plane.h
include/dt-bindings/sound/cs42l42.h [new file with mode: 0644]
include/linux/acpi.h
include/linux/bpf_verifier.h
include/linux/ceph/osd_client.h
include/linux/clk-provider.h
include/linux/compiler-gcc.h
include/linux/console.h
include/linux/cpufreq.h
include/linux/cpuhotplug.h
include/linux/frontswap.h
include/linux/fs.h
include/linux/huge_mm.h
include/linux/hyperv.h
include/linux/intel-iommu.h
include/linux/io.h
include/linux/iomap.h
include/linux/ipv6.h
include/linux/irqchip/arm-gic-v3.h
include/linux/kasan.h
include/linux/kconfig.h
include/linux/libnvdimm.h
include/linux/mlx4/device.h
include/linux/mlx5/driver.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/mtd/nand.h
include/linux/netdevice.h
include/linux/nvme.h
include/linux/of_mdio.h
include/linux/pagemap.h
include/linux/pci.h
include/linux/perf_event.h
include/linux/phy/phy.h
include/linux/qed/qed_if.h
include/linux/qed/qede_roce.h
include/linux/regmap.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/sunrpc/svc_xprt.h
include/linux/syscalls.h
include/linux/thread_info.h
include/linux/usb/cdc_ncm.h
include/net/addrconf.h
include/net/bluetooth/hci_core.h
include/net/cfg80211.h
include/net/gro_cells.h
include/net/if_inet6.h
include/net/ip.h
include/net/ip6_fib.h
include/net/ip6_route.h
include/net/ip6_tunnel.h
include/net/ip_fib.h
include/net/ipv6.h
include/net/mac80211.h
include/net/net_namespace.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_labels.h
include/net/netfilter/nf_tables.h
include/net/sctp/sctp.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
include/net/vxlan.h
include/sound/cs35l34.h [new file with mode: 0644]
include/sound/dmaengine_pcm.h
include/sound/rt5514.h [new file with mode: 0644]
include/sound/rt5665.h [new file with mode: 0755]
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/target/target_core_base.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/Kbuild
include/uapi/linux/atm_zatm.h
include/uapi/linux/bpqether.h
include/uapi/linux/bt-bmc.h [new file with mode: 0644]
include/uapi/linux/can.h
include/uapi/linux/ethtool.h
include/uapi/linux/if.h
include/uapi/linux/input-event-codes.h
include/uapi/linux/kvm.h
include/uapi/linux/netfilter/Kbuild
include/uapi/linux/rtnetlink.h
include/uapi/linux/tc_act/Kbuild
include/uapi/sound/asoc.h
include/uapi/sound/snd_sst_tokens.h
init/do_mounts_rd.c
ipc/msgutil.c
kernel/bpf/hashtab.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cpu.c
kernel/events/core.c
kernel/events/uprobes.c
kernel/exit.c
kernel/fork.c
kernel/irq/manage.c
kernel/kcov.c
kernel/locking/lockdep.c
kernel/locking/lockdep_internals.h
kernel/locking/rtmutex.c
kernel/locking/rtmutex_common.h
kernel/module.c
kernel/power/suspend.c
kernel/power/suspend_test.c
kernel/printk/printk.c
kernel/ptrace.c
kernel/sched/auto_group.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sched/wait.c
kernel/softirq.c
kernel/taskstats.c
kernel/time/alarmtimer.c
kernel/time/timer.c
kernel/trace/ftrace.c
lib/Kconfig.debug
lib/debugobjects.c
lib/genalloc.c
lib/iov_iter.c
lib/locking-selftest.c
lib/mpi/mpi-pow.c
lib/stackdepot.c
lib/test_bpf.c
lib/test_kasan.c
mm/Kconfig
mm/cma.c
mm/filemap.c
mm/frame_vector.c
mm/gup.c
mm/huge_memory.c
mm/hugetlb.c
mm/kasan/kasan.c
mm/kasan/kasan.h
mm/kasan/report.c
mm/khugepaged.c
mm/kmemleak.c
mm/list_lru.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/mlock.c
mm/mprotect.c
mm/mremap.c
mm/nommu.c
mm/page_alloc.c
mm/process_vm_access.c
mm/shmem.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/swapfile.c
mm/truncate.c
mm/util.c
mm/vmscan.c
mm/workingset.c
net/8021q/vlan.c
net/batman-adv/log.h
net/batman-adv/originator.c
net/batman-adv/tp_meter.c
net/batman-adv/translation-table.c
net/bluetooth/6lowpan.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_request.c
net/bluetooth/hci_request.h
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bridge/br_multicast.c
net/bridge/br_sysfs_br.c
net/caif/caif_socket.c
net/can/bcm.c
net/can/raw.c
net/ceph/ceph_fs.c
net/ceph/osd_client.c
net/ceph/pagevec.c
net/core/dev.c
net/core/ethtool.c
net/core/filter.c
net/core/flow.c
net/core/flow_dissector.c
net/core/net_namespace.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/sock.c
net/core/sock_reuseport.c
net/dcb/dcbnl.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/proto.c
net/dsa/dsa.c
net/dsa/dsa2.c
net/dsa/slave.c
net/ethernet/eth.c
net/hsr/hsr_forward.c
net/ipv4/Kconfig
net/ipv4/af_inet.c
net/ipv4/esp4.c
net/ipv4/fib_frontend.c
net/ipv4/fib_trie.c
net/ipv4/fou.c
net/ipv4/gre_offload.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_forward.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ipmr.c
net/ipv4/netfilter.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/nft_dup_ipv4.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_dctcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv4/udp_impl.h
net/ipv4/udp_offload.c
net/ipv4/udplite.c
net/ipv6/addrconf.c
net/ipv6/datagram.c
net/ipv6/esp6.c
net/ipv6/icmp.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_udp_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
net/ipv6/netfilter/nf_reject_ipv6.c
net/ipv6/netfilter/nft_dup_ipv6.c
net/ipv6/output_core.c
net/ipv6/ping.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/udp_impl.h
net/ipv6/udplite.c
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_ip6.c
net/mac80211/aes_ccm.c
net/mac80211/aes_ccm.h
net/mac80211/aes_gcm.c
net/mac80211/aes_gcm.h
net/mac80211/aes_gmac.c
net/mac80211/aes_gmac.h
net/mac80211/offchannel.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/tx.c
net/mac80211/vht.c
net/mac80211/wpa.c
net/mpls/af_mpls.c
net/ncsi/internal.h
net/ncsi/ncsi-aen.c
net/ncsi/ncsi-manage.c
net/netfilter/core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_internals.h
net/netfilter/nf_nat_core.c
net/netfilter/nf_queue.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_dynset.c
net/netfilter/nft_exthdr.c
net/netfilter/nft_hash.c
net/netfilter/nft_range.c
net/netfilter/nft_set_hash.c
net/netfilter/nft_set_rbtree.c
net/netfilter/x_tables.c
net/netfilter/xt_NFLOG.c
net/netfilter/xt_connmark.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_ipcomp.c
net/netlink/af_netlink.c
net/netlink/af_netlink.h
net/netlink/diag.c
net/netlink/genetlink.c
net/openvswitch/conntrack.c
net/packet/af_packet.c
net/rds/Makefile
net/rds/rds.h
net/rds/tcp.c
net/rxrpc/call_object.c
net/rxrpc/peer_object.c
net/sched/act_api.c
net/sched/act_mirred.c
net/sched/act_pedit.c
net/sched/cls_api.c
net/sched/cls_basic.c
net/sched/cls_bpf.c
net/sched/cls_cgroup.c
net/sched/cls_flow.c
net/sched/cls_flower.c
net/sched/cls_matchall.c
net/sched/cls_rsvp.h
net/sched/cls_tcindex.c
net/sctp/input.c
net/sctp/ipv6.c
net/sctp/output.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/socket.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/clnt.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/sunrpc/xprtsock.c
net/switchdev/switchdev.c
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/link.c
net/tipc/monitor.c
net/tipc/msg.h
net/tipc/name_distr.c
net/tipc/node.c
net/tipc/socket.c
net/tipc/udp_media.c
net/unix/af_unix.c
net/wireless/core.h
net/wireless/scan.c
net/wireless/sysfs.c
net/wireless/util.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
samples/bpf/Makefile
samples/bpf/bpf_helpers.h
samples/bpf/parse_ldabs.c
samples/bpf/parse_simple.c
samples/bpf/parse_varlen.c
samples/bpf/sampleip_kern.c
samples/bpf/tc_l2_redirect.sh [new file with mode: 0755]
samples/bpf/tc_l2_redirect_kern.c [new file with mode: 0644]
samples/bpf/tc_l2_redirect_user.c [new file with mode: 0644]
samples/bpf/tcbpf1_kern.c
samples/bpf/tcbpf2_kern.c
samples/bpf/test_cgrp2_tc_kern.c
samples/bpf/trace_event_kern.c
scripts/Makefile.build
scripts/Makefile.extrawarn
scripts/Makefile.ubsan
scripts/bloat-o-meter
scripts/gcc-plugins/cyc_complexity_plugin.c
scripts/gcc-plugins/gcc-common.h
scripts/gcc-plugins/latent_entropy_plugin.c
scripts/gcc-plugins/sancov_plugin.c
scripts/gcc-x86_64-has-stack-protector.sh
scripts/kconfig/Makefile
security/apparmor/domain.c
security/keys/Kconfig
security/keys/big_key.c
security/keys/proc.c
security/selinux/hooks.c
security/tomoyo/domain.c
sound/core/info.c
sound/core/seq/seq_timer.c
sound/pci/asihpi/hpioctl.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/thinkpad_helper.c
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_ssc_dai.h
sound/soc/atmel/atmel_wm8904.c
sound/soc/atmel/tse850-pcm5142.c [new file with mode: 0644]
sound/soc/bcm/Kconfig
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/adau17x1.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4641.h [deleted file]
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs35l34.c [new file with mode: 0644]
sound/soc/codecs/cs35l34.h [new file with mode: 0644]
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs42l42.c [new file with mode: 0644]
sound/soc/codecs/cs42l42.h [new file with mode: 0644]
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/cs47l24.c
sound/soc/codecs/da7219-aad.c
sound/soc/codecs/da7219.c
sound/soc/codecs/da7219.h
sound/soc/codecs/es8328.h
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/msm8916-wcd-analog.c [new file with mode: 0644]
sound/soc/codecs/msm8916-wcd-digital.c [new file with mode: 0644]
sound/soc/codecs/nau8825.c
sound/soc/codecs/nau8825.h
sound/soc/codecs/rl6231.c
sound/soc/codecs/rl6347a.c
sound/soc/codecs/rt298.c
sound/soc/codecs/rt5514-spi.c
sound/soc/codecs/rt5514.c
sound/soc/codecs/rt5514.h
sound/soc/codecs/rt5616.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.h
sound/soc/codecs/rt5660.c
sound/soc/codecs/rt5660.h
sound/soc/codecs/rt5663.c
sound/soc/codecs/rt5665.c [new file with mode: 0644]
sound/soc/codecs/rt5665.h [new file with mode: 0644]
sound/soc/codecs/sti-sas.c
sound/soc/codecs/tas571x.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm8998.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/wmfw.h
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/imx-wm8962.c
sound/soc/generic/simple-card.c
sound/soc/generic/simple-scu-card.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst.h
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/atom/sst/sst_ipc.c
sound/soc/intel/atom/sst/sst_stream.c
sound/soc/intel/baytrail/sst-baytrail-ipc.c
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/broadwell.c
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/haswell.c
sound/soc/intel/boards/mfld_machine.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/common/sst-acpi.h
sound/soc/intel/common/sst-ipc.c
sound/soc/intel/common/sst-ipc.h
sound/soc/intel/common/sst-match-acpi.c
sound/soc/intel/haswell/sst-haswell-ipc.c
sound/soc/intel/skylake/bxt-sst.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-sst-cldma.c
sound/soc/intel/skylake/skl-sst-dsp.h
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst-utils.c
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h
sound/soc/kirkwood/armada-370-db.c
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/pxa/Kconfig
sound/soc/pxa/corgi.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/magician.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa-ssp.h
sound/soc/pxa/pxa2xx-i2s.h
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/qcom/apq8016_sbc.c
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/lpass-platform.c
sound/soc/qcom/lpass.h
sound/soc/qcom/storm.c
sound/soc/rockchip/rk3399_gru_sound.c
sound/soc/rockchip/rockchip_max98090.c
sound/soc/rockchip/rockchip_rt5645.c
sound/soc/samsung/ac97.c
sound/soc/samsung/dmaengine.c
sound/soc/samsung/i2s.c
sound/soc/samsung/pcm.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/spdif.c
sound/soc/sh/Kconfig
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssiu.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-generic-dmaengine-pcm.c
sound/soc/soc-pcm.c
sound/soc/soc-utils.c
sound/soc/sti/uniperif_player.c
sound/soc/sunxi/sun4i-codec.c
sound/sparc/dbri.c
sound/usb/card.c
sound/usb/quirks-table.h
tools/arch/x86/include/asm/cpufeatures.h
tools/objtool/arch/x86/decode.c
tools/objtool/builtin-check.c
tools/perf/jvmti/Makefile
tools/perf/ui/browsers/hists.c
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/parse-events.l
tools/power/acpi/Makefile.config
tools/power/acpi/Makefile.rules
tools/power/acpi/tools/acpidbg/Makefile
tools/power/acpi/tools/acpidbg/acpidbg.c
tools/power/acpi/tools/acpidump/Makefile
tools/power/cpupower/utils/cpufreq-set.c
tools/testing/nvdimm/Kbuild
tools/testing/nvdimm/test/iomap.c
tools/testing/nvdimm/test/nfit.c
tools/testing/nvdimm/test/nfit_test.h
tools/virtio/ringtest/Makefile
tools/virtio/ringtest/main.c
tools/virtio/ringtest/main.h
tools/virtio/ringtest/noring.c
tools/virtio/ringtest/ptr_ring.c
tools/virtio/ringtest/ring.c
tools/virtio/ringtest/virtio_ring_0_9.c
virt/kvm/arm/pmu.c
virt/kvm/arm/vgic/vgic-mmio.c
virt/kvm/arm/vgic/vgic-mmio.h
virt/kvm/arm/vgic/vgic-v2.c
virt/kvm/arm/vgic/vgic-v3.c
virt/kvm/arm/vgic/vgic.c
virt/kvm/async_pf.c
virt/kvm/eventfd.c
virt/kvm/kvm_main.c

diff --git a/CREDITS b/CREDITS
index 513aaa3546bff3fa1d95c21bf4c9d9b2da2daa4f..d7ebdfbc4d4fae70cb1bc11d82503c2c92a6d27c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -9,7 +9,7 @@
                        Linus
 ----------
 
-M: Matt Mackal
+N: Matt Mackal
 E: mpm@selenic.com
 D: SLOB slab allocator
 
@@ -1864,10 +1864,11 @@ S: The Netherlands
 
 N: Martin Kepplinger
 E: martink@posteo.de
-E: martin.kepplinger@theobroma-systems.com
+E: martin.kepplinger@ginzinger.com
 W: http://www.martinkepplinger.com
 D: mma8452 accelerators iio driver
-D: Kernel cleanups
+D: pegasus_notetaker input driver
+D: Kernel fixes and cleanups
 S: Garnisonstraße 26
 S: 4020 Linz
 S: Austria
@@ -1909,7 +1910,7 @@ S: Ra'annana, Israel
 
 N: Andi Kleen
 E: andi@firstfloor.org
-U: http://www.halobates.de
+W: http://www.halobates.de
 D: network, x86, NUMA, various hacks
 S: Schwalbenstr. 96
 S: 85551 Ottobrunn
@@ -2088,8 +2089,8 @@ D: ST Microelectronics SPEAr13xx PCI host bridge driver
 D: Synopsys Designware PCI host bridge driver
 
 N: Gabor Kuti
-M: seasons@falcon.sch.bme.hu
-M: seasons@makosteszta.sote.hu
+E: seasons@falcon.sch.bme.hu
+E: seasons@makosteszta.sote.hu
 D: Original author of software suspend
 
 N: Jaroslav Kysela
index 4ba0a2a61926251edf33e5f94a4eff45028d44a8..640f65e79ef1c00c94508b6b9f9fe8b63a1305a6 100644 (file)
@@ -220,8 +220,11 @@ What:           /sys/class/cxl/<card>/reset
 Date:           October 2014
 Contact:        linuxppc-dev@lists.ozlabs.org
 Description:    write only
-                Writing 1 will issue a PERST to card which may cause the card
-                to reload the FPGA depending on load_image_on_perst.
+                Writing 1 will issue a PERST to card provided there are no
+                contexts active on any one of the card AFUs. This may cause
+                the card to reload the FPGA depending on load_image_on_perst.
+                Writing -1 will do a force PERST irrespective of any active
+                contexts on the card AFUs.
 Users:         https://github.com/ibm-capi/libcxl
 
 What:          /sys/class/cxl/<card>/perst_reloads_same_image (not in a guest)
index b82deeaec314b8ff711b122282396340496946c8..470def06ab0a42e40f860d1fe54f8e0d489ec4c3 100644 (file)
@@ -1,4 +1,4 @@
-What:           state
+What:           /sys/devices/system/ibm_rtl/state
 Date:           Sep 2010
 KernelVersion:  2.6.37
 Contact:        Vernon Mauery <vernux@us.ibm.com>
@@ -10,7 +10,7 @@ Description:    The state file allows a means by which to change in and
 Users:          The ibm-prtm userspace daemon uses this interface.
 
 
-What:           version
+What:           /sys/devices/system/ibm_rtl/version
 Date:           Sep 2010
 KernelVersion:  2.6.37
 Contact:        Vernon Mauery <vernux@us.ibm.com>
diff --git a/Documentation/ABI/testing/sysfs-platform-sst-atom b/Documentation/ABI/testing/sysfs-platform-sst-atom
new file mode 100644 (file)
index 0000000..0d07c03
--- /dev/null
@@ -0,0 +1,17 @@
+What:          /sys/devices/platform/8086%x:00/firmware_version
+Date:          November 2016
+KernelVersion: 4.10
+Contact:       "Sebastien Guiriec" <sebastien.guiriec@intel.com>
+Description:
+               LPE Firmware version for SST driver on all atom
+               plaforms (BYT/CHT/Merrifield/BSW).
+               If the FW has never been loaded it will display:
+                       "FW not yet loaded"
+               If FW has been loaded it will display:
+                       "v01.aa.bb.cc"
+               aa: Major version is reflecting SoC version:
+                       0d: BYT FW
+                       0b: BSW FW
+                       07: Merrifield FW
+               bb: Minor version
+               cc: Build version
index e5b6497116f41be1a6e91e9d59b77a0991eabfa1..c75b64a85859fbca05571093c02799a25f994e1a 100644 (file)
@@ -309,3 +309,4 @@ Version History
        with a reshape in progress.
 1.9.0   Add support for RAID level takeover/reshape/region size
        and set size reduction.
+1.9.1   Fix activation of existing RAID 4/10 mapped devices
index c7179d3b5c33e11d0f8b1af713cc7625b96ecfd5..812163060fa3e4cb4e4f39fe22c9fbd2aeb41d9f 100644 (file)
@@ -24,7 +24,7 @@ Example:
                reg = <0x61840000 0x4000>;
 
                clock {
-                       compatible = "socionext,uniphier-ld20-clock";
+                       compatible = "socionext,uniphier-ld11-clock";
                        #clock-cells = <1>;
                };
 
@@ -43,8 +43,8 @@ Provided clocks:
 21: USB3 ch1 PHY1
 
 
-Media I/O (MIO) clock
----------------------
+Media I/O (MIO) clock, SD clock
+-------------------------------
 
 Required properties:
 - compatible: should be one of the following:
@@ -52,10 +52,10 @@ Required properties:
     "socionext,uniphier-ld4-mio-clock"  - for LD4 SoC.
     "socionext,uniphier-pro4-mio-clock" - for Pro4 SoC.
     "socionext,uniphier-sld8-mio-clock" - for sLD8 SoC.
-    "socionext,uniphier-pro5-mio-clock" - for Pro5 SoC.
-    "socionext,uniphier-pxs2-mio-clock" - for PXs2/LD6b SoC.
+    "socionext,uniphier-pro5-sd-clock"  - for Pro5 SoC.
+    "socionext,uniphier-pxs2-sd-clock"  - for PXs2/LD6b SoC.
     "socionext,uniphier-ld11-mio-clock" - for LD11 SoC.
-    "socionext,uniphier-ld20-mio-clock" - for LD20 SoC.
+    "socionext,uniphier-ld20-sd-clock"  - for LD20 SoC.
 - #clock-cells: should be 1.
 
 Example:
@@ -66,7 +66,7 @@ Example:
                reg = <0x59810000 0x800>;
 
                clock {
-                       compatible = "socionext,uniphier-ld20-mio-clock";
+                       compatible = "socionext,uniphier-ld11-mio-clock";
                        #clock-cells = <1>;
                };
 
@@ -112,7 +112,7 @@ Example:
                reg = <0x59820000 0x200>;
 
                clock {
-                       compatible = "socionext,uniphier-ld20-peri-clock";
+                       compatible = "socionext,uniphier-ld11-peri-clock";
                        #clock-cells = <1>;
                };
 
diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
new file mode 100644 (file)
index 0000000..6f28969
--- /dev/null
@@ -0,0 +1,23 @@
+* Aspeed BT (Block Transfer) IPMI interface
+
+The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs
+(BaseBoard Management Controllers) and the BT interface can be used to
+perform in-band IPMI communication with their host.
+
+Required properties:
+
+- compatible : should be "aspeed,ast2400-ibt-bmc"
+- reg: physical address and size of the registers
+
+Optional properties:
+
+- interrupts: interrupt generated by the BT interface. without an
+  interrupt, the driver will operate in poll mode.
+
+Example:
+
+       ibt@1e789140 {
+               compatible = "aspeed,ast2400-ibt-bmc";
+               reg = <0x1e789140 0x18>;
+               interrupts = <8>;
+       };
index 4e00e859e885a0ce8ae59ae234b2637f2e894e70..bfa461aaac99b3e3033727572009c308efc3b6bf 100644 (file)
@@ -43,6 +43,9 @@ Optional properties:
   reset signal present internally in some host controller IC designs.
   See Documentation/devicetree/bindings/reset/reset.txt for details.
 
+* reset-names: request name for using "resets" property. Must be "reset".
+       (It will be used together with "resets" property.)
+
 * clocks: from common clock binding: handle to biu and ciu clocks for the
   bus interface unit clock and the card interface unit clock.
 
@@ -103,6 +106,8 @@ board specific portions as listed below.
                interrupts = <0 75 0>;
                #address-cells = <1>;
                #size-cells = <0>;
+               resets = <&rst 20>;
+               reset-names = "reset";
        };
 
 [board specific internal DMA resources]
index e1d76812419cad0dcba664263ac09d12b90f069c..05150957ecfda1bdee82f716fc7a00c70f9aa713 100644 (file)
@@ -9,10 +9,26 @@ The following properties are common to the Ethernet controllers:
 - max-speed: number, specifies maximum speed in Mbit/s supported by the device;
 - max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than
   the maximum frame size (there's contradiction in ePAPR).
-- phy-mode: string, operation mode of the PHY interface; supported values are
-  "mii", "gmii", "sgmii", "qsgmii", "tbi", "rev-mii", "rmii", "rgmii", "rgmii-id",
-  "rgmii-rxid", "rgmii-txid", "rtbi", "smii", "xgmii", "trgmii"; this is now a
-  de-facto standard property;
+- phy-mode: string, operation mode of the PHY interface. This is now a de-facto
+  standard property; supported values are:
+  * "mii"
+  * "gmii"
+  * "sgmii"
+  * "qsgmii"
+  * "tbi"
+  * "rev-mii"
+  * "rmii"
+  * "rgmii" (RX and TX delays are added by the MAC when required)
+  * "rgmii-id" (RGMII with internal RX and TX delays provided by the PHY, the
+     MAC should not add the RX or TX delays in this case)
+  * "rgmii-rxid" (RGMII with internal RX delay provided by the PHY, the MAC
+     should not add an RX delay in this case)
+  * "rgmii-txid" (RGMII with internal TX delay provided by the PHY, the MAC
+     should not add an TX delay in this case)
+  * "rtbi"
+  * "smii"
+  * "xgmii"
+  * "trgmii"
 - phy-connection-type: the same as "phy-mode" property but described in ePAPR;
 - phy-handle: phandle, specifies a reference to a node representing a PHY
   device; this property is described in ePAPR and so preferred;
index bce52b2ec55ece41a14b997772956e077a7259e6..6fd988c84c4f9f4d7eb7df2f2c52283c27d164d1 100644 (file)
@@ -49,6 +49,7 @@ Optional port properties:
 and
 
  - phy-handle: See ethernet.txt file in the same directory.
+ - phy-mode: See ethernet.txt file in the same directory.
 
 or
 
index ba67b39939c10b15f7e1a99291c935a1c2c81bf8..71aeda1ca05598d74e8db3f429f212d0095f702a 100644 (file)
@@ -26,13 +26,16 @@ Required properties:
        - "sys"
        - "legacy"
        - "client"
-- resets: Must contain five entries for each entry in reset-names.
+- resets: Must contain seven entries for each entry in reset-names.
           See ../reset/reset.txt for details.
 - reset-names: Must include the following names
        - "core"
        - "mgmt"
        - "mgmt-sticky"
        - "pipe"
+       - "pm"
+       - "aclk"
+       - "pclk"
 - pinctrl-names : The pin control state names
 - pinctrl-0: The "default" pinctrl state
 - #interrupt-cells: specifies the number of cells needed to encode an
@@ -86,8 +89,10 @@ pcie0: pcie@f8000000 {
        reg = <0x0 0xf8000000 0x0 0x2000000>, <0x0 0xfd000000 0x0 0x1000000>;
        reg-names = "axi-base", "apb-base";
        resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
-                <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
-       reset-names = "core", "mgmt", "mgmt-sticky", "pipe";
+                <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE> ,
+                <&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>, <&cru SRST_A_PCIE>;
+       reset-names = "core", "mgmt", "mgmt-sticky", "pipe",
+                     "pm", "pclk", "aclk";
        phys = <&pcie_phy>;
        phy-names = "pcie-phy";
        pinctrl-names = "default";
index 5e60ad18f147c2399b418026968068a9ccc7cf0d..2ad18c4ea55c5f022f0181c78896d5a8e33d4e74 100644 (file)
@@ -43,7 +43,9 @@ aspeed,ast2500-pinctrl, aspeed,g5-pinctrl:
 
 GPID0 GPID2 GPIE0 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8
 I2C9 MAC1LINK MDIO1 MDIO2 OSCCLK PEWAKE PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7
-RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8
+RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 SPI1DEBUG SPI1PASSTHRU TIMER4 TIMER5 TIMER6
+TIMER7 TIMER8 VGABIOSROM
+
 
 Examples:
 
index f9753c416974d553cce347f2fbf3c82bc56d9afc..b24583aa34c3bf45363e3eee4ceac292d713b67d 100644 (file)
@@ -14,11 +14,6 @@ Required properies:
  - #size-cells : The value of this property must be 1
  - ranges      : defines mapping between pin controller node (parent) to
    gpio-bank node (children).
- - interrupt-parent: phandle of the interrupt parent to which the external
-   GPIO interrupts are forwarded to.
- - st,syscfg: Should be phandle/offset pair. The phandle to the syscon node
-   which includes IRQ mux selection register, and the offset of the IRQ mux
-   selection register.
  - pins-are-numbered: Specify the subnodes are using numbered pinmux to
    specify pins.
 
@@ -37,6 +32,11 @@ Required properties:
 
 Optional properties:
  - reset:        : Reference to the reset controller
+ - interrupt-parent: phandle of the interrupt parent to which the external
+   GPIO interrupts are forwarded to.
+ - st,syscfg: Should be phandle/offset pair. The phandle to the syscon node
+   which includes IRQ mux selection register, and the offset of the IRQ mux
+   selection register.
 
 Example:
 #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
index e6bbfccd56c326214d4d7cdaf78c664f34f863e5..5020524cddebf70ddaedeeb6b61bd47bdcb0a4a1 100644 (file)
@@ -6,25 +6,25 @@ System reset
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-reset" - for PH1-sLD3 SoC.
-    "socionext,uniphier-ld4-reset"  - for PH1-LD4 SoC.
-    "socionext,uniphier-pro4-reset" - for PH1-Pro4 SoC.
-    "socionext,uniphier-sld8-reset" - for PH1-sLD8 SoC.
-    "socionext,uniphier-pro5-reset" - for PH1-Pro5 SoC.
-    "socionext,uniphier-pxs2-reset" - for ProXstream2/PH1-LD6b SoC.
-    "socionext,uniphier-ld11-reset" - for PH1-LD11 SoC.
-    "socionext,uniphier-ld20-reset" - for PH1-LD20 SoC.
+    "socionext,uniphier-sld3-reset" - for sLD3 SoC.
+    "socionext,uniphier-ld4-reset"  - for LD4 SoC.
+    "socionext,uniphier-pro4-reset" - for Pro4 SoC.
+    "socionext,uniphier-sld8-reset" - for sLD8 SoC.
+    "socionext,uniphier-pro5-reset" - for Pro5 SoC.
+    "socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC.
+    "socionext,uniphier-ld11-reset" - for LD11 SoC.
+    "socionext,uniphier-ld20-reset" - for LD20 SoC.
 - #reset-cells: should be 1.
 
 Example:
 
        sysctrl@61840000 {
-               compatible = "socionext,uniphier-ld20-sysctrl",
+               compatible = "socionext,uniphier-ld11-sysctrl",
                             "simple-mfd", "syscon";
                reg = <0x61840000 0x4000>;
 
                reset {
-                       compatible = "socionext,uniphier-ld20-reset";
+                       compatible = "socionext,uniphier-ld11-reset";
                        #reset-cells = <1>;
                };
 
@@ -32,30 +32,30 @@ Example:
        };
 
 
-Media I/O (MIO) reset
----------------------
+Media I/O (MIO) reset, SD reset
+-------------------------------
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-sld3-mio-reset" - for PH1-sLD3 SoC.
-    "socionext,uniphier-ld4-mio-reset"  - for PH1-LD4 SoC.
-    "socionext,uniphier-pro4-mio-reset" - for PH1-Pro4 SoC.
-    "socionext,uniphier-sld8-mio-reset" - for PH1-sLD8 SoC.
-    "socionext,uniphier-pro5-mio-reset" - for PH1-Pro5 SoC.
-    "socionext,uniphier-pxs2-mio-reset" - for ProXstream2/PH1-LD6b SoC.
-    "socionext,uniphier-ld11-mio-reset" - for PH1-LD11 SoC.
-    "socionext,uniphier-ld20-mio-reset" - for PH1-LD20 SoC.
+    "socionext,uniphier-sld3-mio-reset" - for sLD3 SoC.
+    "socionext,uniphier-ld4-mio-reset"  - for LD4 SoC.
+    "socionext,uniphier-pro4-mio-reset" - for Pro4 SoC.
+    "socionext,uniphier-sld8-mio-reset" - for sLD8 SoC.
+    "socionext,uniphier-pro5-sd-reset"  - for Pro5 SoC.
+    "socionext,uniphier-pxs2-sd-reset"  - for PXs2/LD6b SoC.
+    "socionext,uniphier-ld11-mio-reset" - for LD11 SoC.
+    "socionext,uniphier-ld20-sd-reset"  - for LD20 SoC.
 - #reset-cells: should be 1.
 
 Example:
 
        mioctrl@59810000 {
-               compatible = "socionext,uniphier-ld20-mioctrl",
+               compatible = "socionext,uniphier-ld11-mioctrl",
                             "simple-mfd", "syscon";
                reg = <0x59810000 0x800>;
 
                reset {
-                       compatible = "socionext,uniphier-ld20-mio-reset";
+                       compatible = "socionext,uniphier-ld11-mio-reset";
                        #reset-cells = <1>;
                };
 
@@ -68,24 +68,24 @@ Peripheral reset
 
 Required properties:
 - compatible: should be one of the following:
-    "socionext,uniphier-ld4-peri-reset"  - for PH1-LD4 SoC.
-    "socionext,uniphier-pro4-peri-reset" - for PH1-Pro4 SoC.
-    "socionext,uniphier-sld8-peri-reset" - for PH1-sLD8 SoC.
-    "socionext,uniphier-pro5-peri-reset" - for PH1-Pro5 SoC.
-    "socionext,uniphier-pxs2-peri-reset" - for ProXstream2/PH1-LD6b SoC.
-    "socionext,uniphier-ld11-peri-reset" - for PH1-LD11 SoC.
-    "socionext,uniphier-ld20-peri-reset" - for PH1-LD20 SoC.
+    "socionext,uniphier-ld4-peri-reset"  - for LD4 SoC.
+    "socionext,uniphier-pro4-peri-reset" - for Pro4 SoC.
+    "socionext,uniphier-sld8-peri-reset" - for sLD8 SoC.
+    "socionext,uniphier-pro5-peri-reset" - for Pro5 SoC.
+    "socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC.
+    "socionext,uniphier-ld11-peri-reset" - for LD11 SoC.
+    "socionext,uniphier-ld20-peri-reset" - for LD20 SoC.
 - #reset-cells: should be 1.
 
 Example:
 
        perictrl@59820000 {
-               compatible = "socionext,uniphier-ld20-perictrl",
+               compatible = "socionext,uniphier-ld11-perictrl",
                             "simple-mfd", "syscon";
                reg = <0x59820000 0x200>;
 
                reset {
-                       compatible = "socionext,uniphier-ld20-peri-reset";
+                       compatible = "socionext,uniphier-ld11-peri-reset";
                        #reset-cells = <1>;
                };
 
index a3eb154c32caf9f273c8801811565722a3201e38..227bb770b0276af8cb716bd89d88e8c055c168f8 100644 (file)
@@ -1,7 +1,9 @@
 Binding for Cadence UART Controller
 
 Required properties:
-- compatible : should be "cdns,uart-r1p8", or "xlnx,xuartps"
+- compatible :
+  Use "xlnx,xuartps","cdns,uart-r1p8" for Zynq-7xxx SoC.
+  Use "xlnx,zynqmp-uart","cdns,uart-r1p12" for Zynq Ultrascale+ MPSoC.
 - reg: Should contain UART controller registers location and length.
 - interrupts: Should contain UART controller interrupts.
 - clocks: Must contain phandles to the UART clocks
index 1e4000d83aee06828c974000e5122567b8fda631..8d27d1a603e7bf755c8451186cdb507dd1d50a58 100644 (file)
@@ -9,6 +9,14 @@ Required properties:
     - "renesas,scifb-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFB compatible UART.
     - "renesas,scifa-r8a7740" for R8A7740 (R-Mobile A1) SCIFA compatible UART.
     - "renesas,scifb-r8a7740" for R8A7740 (R-Mobile A1) SCIFB compatible UART.
+    - "renesas,scif-r8a7743" for R8A7743 (RZ/G1M) SCIF compatible UART.
+    - "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART.
+    - "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB compatible UART.
+    - "renesas,hscif-r8a7743" for R8A7743 (RZ/G1M) HSCIF compatible UART.
+    - "renesas,scif-r8a7745" for R8A7745 (RZ/G1E) SCIF compatible UART.
+    - "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
+    - "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
+    - "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART.
     - "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART.
     - "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
     - "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.
diff --git a/Documentation/devicetree/bindings/sound/axentia,tse850-pcm5142.txt b/Documentation/devicetree/bindings/sound/axentia,tse850-pcm5142.txt
new file mode 100644 (file)
index 0000000..5b9b38f
--- /dev/null
@@ -0,0 +1,88 @@
+Devicetree bindings for the Axentia TSE-850 audio complex
+
+Required properties:
+  - compatible: "axentia,tse850-pcm5142"
+  - axentia,ssc-controller: The phandle of the atmel SSC controller used as
+    cpu dai.
+  - axentia,audio-codec: The phandle of the PCM5142 codec.
+  - axentia,add-gpios: gpio specifier that controls the mixer.
+  - axentia,loop1-gpios: gpio specifier that controls loop relays on channel 1.
+  - axentia,loop2-gpios: gpio specifier that controls loop relays on channel 2.
+  - axentia,ana-supply: Regulator that supplies the output amplifier. Must
+    support voltages in the 2V - 20V range, in 1V steps.
+
+The schematics explaining the gpios are as follows:
+
+               loop1 relays
+   IN1 +---o  +------------+  o---+ OUT1
+            \                /
+             +              +
+             |   /          |
+             +--o  +--.     |
+             |  add   |     |
+             |        V     |
+             |      .---.   |
+   DAC +----------->|Sum|---+
+             |      '---'   |
+             |              |
+             +              +
+
+   IN2 +---o--+------------+--o---+ OUT2
+               loop2 relays
+
+The 'loop1' gpio pin controlls two relays, which are either in loop position,
+meaning that input and output are directly connected, or they are in mixer
+position, meaning that the signal is passed through the 'Sum' mixer. Similarly
+for 'loop2'.
+
+In the above, the 'loop1' relays are inactive, thus feeding IN1 to the mixer
+(if 'add' is active) and feeding the mixer output to OUT1. The 'loop2' relays
+are active, short-cutting the TSE-850 from channel 2. IN1, IN2, OUT1 and OUT2
+are TSE-850 connectors and DAC is the PCB name of the (filtered) output from
+the PCM5142 codec.
+
+Example:
+
+       &i2c {
+               codec: pcm5142@4c {
+                       compatible = "ti,pcm5142";
+
+                       reg = <0x4c>;
+
+                       AVDD-supply = <&reg_3v3>;
+                       DVDD-supply = <&reg_3v3>;
+                       CPVDD-supply = <&reg_3v3>;
+
+                       clocks = <&sck>;
+
+                       pll-in = <3>;
+                       pll-out = <6>;
+               };
+       };
+
+       ana: ana-reg {
+               compatible = "pwm-regulator";
+
+               regulator-name = "ANA";
+
+               pwms = <&pwm0 2 1000 PWM_POLARITY_INVERTED>;
+               pwm-dutycycle-unit = <1000>;
+               pwm-dutycycle-range = <100 1000>;
+
+               regulator-min-microvolt = <2000000>;
+               regulator-max-microvolt = <20000000>;
+               regulator-ramp-delay = <1000>;
+       };
+
+       sound {
+               compatible = "axentia,tse850-pcm5142";
+
+               axentia,ssc-controller = <&ssc0>;
+               axentia,audio-codec = <&codec>;
+
+               axentia,add-gpios = <&pioA 8 GPIO_ACTIVE_LOW>;
+               axentia,loop1-gpios = <&pioA 10 GPIO_ACTIVE_LOW>;
+               axentia,loop2-gpios = <&pioA 11 GPIO_ACTIVE_LOW>;
+
+               axentia,ana-supply = <&ana>;
+       };
diff --git a/Documentation/devicetree/bindings/sound/cs35l34.txt b/Documentation/devicetree/bindings/sound/cs35l34.txt
new file mode 100644 (file)
index 0000000..b218ead
--- /dev/null
@@ -0,0 +1,64 @@
+CS35L34 Speaker Amplifier
+
+Required properties:
+
+  - compatible : "cirrus,cs35l34"
+
+  - reg : the I2C address of the device for I2C.
+
+  - VA-supply, VP-supply : power supplies for the device,
+    as covered in
+    Documentation/devicetree/bindings/regulator/regulator.txt.
+
+  - cirrus,boost-vtge-millivolt : Boost Voltage Value.  Configures the boost
+    converter's output voltage in mV. The range is from VP to 8V with
+    increments of 100mV.
+
+  - cirrus,boost-nanohenry: Inductor value for boost converter. The value is
+    in nH and they can be values of 1000nH, 1100nH, 1200nH, 1500nH, and 2200nH.
+
+Optional properties:
+
+  - reset-gpios: GPIO used to reset the amplifier.
+
+  - interrupt-parent : Specifies the phandle of the interrupt controller to
+    which the IRQs from CS35L34 are delivered to.
+  - interrupts : IRQ line info CS35L34.
+    (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+    for further information relating to interrupt properties)
+
+  - cirrus,boost-peak-milliamp : Boost converter peak current limit in mA. The
+    range starts at 1200mA and goes to a maximum of 3840mA with increments of
+    80mA. The default value is 2480mA.
+
+  - cirrus,i2s-sdinloc : ADSP SDIN I2S channel location. Indicates whether the
+    received mono data is in the left or right portion of the I2S frame
+    according to the AD0 pin or directly via this configuration.
+    0x0 (Default) = Selected by AD0 input (if AD0 = LOW, use left channel),
+    0x2 = Left,
+    0x1 = Selected by the inversion of the AD0 input (if AD0 = LOW, use right
+    channel),
+    0x3 = Right.
+
+  - cirrus,gain-zc-disable: Boolean property. If set, the gain change will take
+    effect without waiting for a zero cross.
+
+  - cirrus,tdm-rising-edge: Boolean property. If set, data is on the rising edge of
+    SCLK. Otherwise, data is on the falling edge of SCLK.
+
+
+Example:
+
+cs35l34: cs35l34@40 {
+       compatible = "cirrus,cs35l34";
+       reg = <0x40>;
+
+       interrupt-parent = <&gpio8>;
+       interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+       reset-gpios = <&gpio 10 0>;
+
+       cirrus,boost-vtge-milltvolt = <8000>; /* 8V */
+       cirrus,boost-ind-nanohenry = <1000>; /* 1uH */
+       cirrus,boost-peak-milliamp = <3000>; /* 3A */
+};
diff --git a/Documentation/devicetree/bindings/sound/cs42l42.txt b/Documentation/devicetree/bindings/sound/cs42l42.txt
new file mode 100644 (file)
index 0000000..9a2c5e2
--- /dev/null
@@ -0,0 +1,110 @@
+CS42L42 audio CODEC
+
+Required properties:
+
+  - compatible : "cirrus,cs42l42"
+
+  - reg : the I2C address of the device for I2C.
+
+  - VP-supply, VCP-supply, VD_FILT-supply, VL-supply, VA-supply :
+  power supplies for the device, as covered in
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Optional properties:
+
+  - reset-gpios : a GPIO spec for the reset pin. If specified, it will be
+  deasserted before communication to the codec starts.
+
+  - interrupt-parent : Specifies the phandle of the interrupt controller to
+  which the IRQs from CS42L42 are delivered to.
+
+  - interrupts : IRQ line info CS42L42.
+  (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+  for further information relating to interrupt properties)
+
+  - cirrus,ts-inv : Boolean property. For jacks that invert the tip sense
+  polarity. Normal jacks will short tip sense pin to HS1 when headphones are
+  plugged in and leave tip sense floating when not plugged in. Inverting jacks
+  short tip sense when unplugged and float when plugged in.
+
+  0 = (Default) Non-inverted
+  1 = Inverted
+
+  - cirrus,ts-dbnc-rise : Debounce the rising edge of TIP_SENSE_PLUG. With no
+  debounce, the tip sense pin might be noisy on a plug event.
+
+  0 - 0ms,
+  1 - 125ms,
+  2 - 250ms,
+  3 - 500ms,
+  4 - 750ms,
+  5 - (Default) 1s,
+  6 - 1.25s,
+  7 - 1.5s,
+
+  - cirrus,ts-dbnc-fall : Debounce the falling edge of TIP_SENSE_UNPLUG.
+  With no debounce, the tip sense pin might be noisy on an unplug event.
+
+  0 - 0ms,
+  1 - 125ms,
+  2 - 250ms,
+  3 - 500ms,
+  4 - 750ms,
+  5 - (Default) 1s,
+  6 - 1.25s,
+  7 - 1.5s,
+
+  - cirrus,btn-det-init-dbnce : This sets how long the driver sleeps after
+  enabling button detection interrupts. After auto-detection and before
+  servicing button interrupts, the HS bias needs time to settle. If you
+  don't wait, there is possibility for erroneous button interrupt.
+
+  0ms - 200ms,
+  Default = 100ms
+
+  - cirrus,btn-det-event-dbnce : This sets how long the driver delays after
+  receiving a button press interrupt. With level detect interrupts, you want
+  to wait a small amount of time to make sure the button press is making a
+  clean connection with the bias resistors.
+
+  0ms - 20ms,
+  Default = 10ms
+
+  - cirrus,bias-lvls : For a level-detect headset button scheme, each button
+  will bias the mic pin to a certain voltage. To determine which button was
+  pressed, the driver will compare this biased voltage to sequential,
+  decreasing voltages and will stop when a comparator is tripped,
+  indicating a comparator voltage < bias voltage. This value represents a
+  percentage of the internally generated HS bias voltage. For different
+  hardware setups, a designer might want to tweak this. This is an array of
+  descending values for the comparator voltage.
+
+  Array of 4 values
+  Each 0-63
+  < x1 x2 x3 x4 >
+  Default = < 15 8 4 1>
+
+
+Example:
+
+cs42l42: cs42l42@48 {
+       compatible = "cirrus,cs42l42";
+       reg = <0x48>;
+       VA-supply = <&dummy_vreg>;
+       VP-supply = <&dummy_vreg>;
+       VCP-supply = <&dummy_vreg>;
+       VD_FILT-supply = <&dummy_vreg>;
+       VL-supply = <&dummy_vreg>;
+
+       reset-gpios = <&axi_gpio_0 1 0>;
+       interrupt-parent = <&gpio0>;
+       interrupts = <55 8>
+
+       cirrus,ts-inv = <0x00>;
+       cirrus,ts-dbnc-rise = <0x05>;
+       cirrus,ts-dbnc-fall = <0x00>;
+       cirrus,btn-det-init-dbnce = <100>;
+       cirrus,btn-det-event-dbnce = <10>;
+       cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>;
+       cirrus,hs-bias-ramp-rate = <0x02>;
+};
\ No newline at end of file
index 55b53e1fd72c9d6e8c3af4804cc4d3f376d9970c..e0b6165c9cfcec19051bf7f8e1c5873374f83a69 100644 (file)
@@ -43,7 +43,7 @@ mcbsp0: mcbsp@1d10000 {
                <0x00310000 0x1000>;
        reg-names = "mpu", "dat";
        interrupts = <97 98>;
-       interrupts-names = "rx", "tx";
+       interrupt-names = "rx", "tx";
        dmas = <&edma0 3 1
                &edma0 2 1>;
        dma-names = "tx", "rx";
index fd40c852d7c7e18c12e5fabc49f0b141614267ac..462b04e8209f4d8de453005b52967ed16a63224b 100644 (file)
@@ -12,7 +12,7 @@ Required properties:
 
 Optional properties:
 - ti,dmic: phandle for the OMAP dmic node if the machine have it connected
-- ti,jack_detection: Need to be present if the board capable to detect jack
+- ti,jack-detection: Need to be present if the board capable to detect jack
   insertion, removal.
 
 Available audio endpoints for the audio-routing table:
index d9d8635ff94ce65faa0f3a5f14333266145f189a..6a4aadc4ce06b27ff059c64f6c438d0fef863b21 100644 (file)
@@ -44,8 +44,7 @@ Required dai-link subnodes:
 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
+-sound-dai             : phandle/s and port of CPU/CODEC
 
 Example:
 
@@ -73,7 +72,7 @@ sound: sound {
                        sound-dai = <&lpass MI2S_PRIMARY>;
                };
                codec {
-                       sound-dai = <&wcd_codec 0>;
+                       sound-dai = <&lpass_codec 0>, <&wcd_codec 0>;
                };
        };
 
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt
new file mode 100644 (file)
index 0000000..ccb401c
--- /dev/null
@@ -0,0 +1,85 @@
+msm8916 analog audio CODEC
+
+Bindings for codec Analog IP which is integrated in pmic pm8916,
+
+## Bindings for codec core on pmic:
+
+Required properties
+ - compatible = "qcom,pm8916-wcd-analog-codec";
+ - reg: represents the slave base address provided to the peripheral.
+ - interrupt-parent : The parent interrupt controller.
+ - interrupts: List of interrupts in given SPMI peripheral.
+ - interrupt-names: Names specified to above list of interrupts in same
+                   order. List of supported interrupt names are:
+  "cdc_spk_cnp_int" - Speaker click and pop interrupt.
+  "cdc_spk_clip_int" - Speaker clip interrupt.
+  "cdc_spk_ocp_int" - Speaker over current protect interrupt.
+  "mbhc_ins_rem_det1" - jack insert removal detect interrupt 1.
+  "mbhc_but_rel_det" - button release interrupt.
+  "mbhc_but_press_det" - button press event
+  "mbhc_ins_rem_det" - jack insert removal detect interrupt.
+  "mbhc_switch_int"    - multi button headset interrupt.
+  "cdc_ear_ocp_int" - Earphone over current protect interrupt.
+  "cdc_hphr_ocp_int" - Headphone R over current protect interrupt.
+  "cdc_hphl_ocp_det" - Headphone L over current protect interrupt.
+  "cdc_ear_cnp_int" - earphone cnp interrupt.
+  "cdc_hphr_cnp_int" - hphr click and pop interrupt.
+  "cdc_hphl_cnp_int" - hphl click and pop interrupt.
+
+ - clocks: Handle to mclk.
+ - clock-names: should be "mclk"
+ - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node.
+ - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node.
+ - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node.
+
+Optional Properties:
+- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor
+                        connected.
+- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor
+                        connected.
+
+Example:
+
+spmi_bus {
+       ...
+       audio-codec@f000{
+               compatible = "qcom,pm8916-wcd-analog-codec";
+               reg = <0xf000 0x200>;
+               reg-names = "pmic-codec-core";
+               clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
+               clock-names = "mclk";
+               interrupt-parent = <&spmi_bus>;
+               interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+               interrupt-names = "cdc_spk_cnp_int",
+                                 "cdc_spk_clip_int",
+                                 "cdc_spk_ocp_int",
+                                 "mbhc_ins_rem_det1",
+                                 "mbhc_but_rel_det",
+                                 "mbhc_but_press_det",
+                                 "mbhc_ins_rem_det",
+                                 "mbhc_switch_int",
+                                 "cdc_ear_ocp_int",
+                                 "cdc_hphr_ocp_int",
+                                 "cdc_hphl_ocp_det",
+                                 "cdc_ear_cnp_int",
+                                 "cdc_hphr_cnp_int",
+                                 "cdc_hphl_cnp_int";
+                      VDD-CDC-IO-supply = <&pm8916_l5>;
+                      VDD-CDC-TX-RX-CX-supply = <&pm8916_l5>;
+                      VDD-MICBIAS-supply = <&pm8916_l13>;
+                      #sound-dai-cells = <1>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt
new file mode 100644 (file)
index 0000000..1c8e4cb
--- /dev/null
@@ -0,0 +1,20 @@
+msm8916 digital audio CODEC
+
+## Bindings for codec core in lpass:
+
+Required properties
+ - compatible = "qcom,msm8916-wcd-digital-codec";
+ - reg: address space for lpass codec.
+ - clocks: Handle to mclk and ahbclk
+ - clock-names: should be "mclk", "ahbix-clk".
+
+Example:
+
+audio-codec@771c000{
+       compatible = "qcom,msm8916-wcd-digital-codec";
+       reg = <0x0771c000 0x400>;
+       clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>,
+                <&gcc GCC_CODEC_DIGCODEC_CLK>;
+       clock-names = "ahbix-clk", "mclk";
+       #sound-dai-cells = <1>;
+};
index 9cabfc18cb57be3dfbeca45a828d185b7e80f52c..929ca6756b02314ca44c9e8786ab32637a3d2294 100644 (file)
@@ -13,6 +13,9 @@ Optional properties:
 - clocks: The phandle of the master clock to the CODEC
 - clock-names: Should be "mclk"
 
+- realtek,dmic-init-delay-ms
+  Set the DMIC initial delay (ms) to wait it ready.
+
 Pins on the device (for linking into audio routes) for RT5514:
 
   * DMIC1L
diff --git a/Documentation/devicetree/bindings/sound/rt5665.txt b/Documentation/devicetree/bindings/sound/rt5665.txt
new file mode 100755 (executable)
index 0000000..419c892
--- /dev/null
@@ -0,0 +1,68 @@
+RT5665/RT5666/RT5668 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : One of "realtek,rt5665", "realtek,rt5666" or "realtek,rt5668".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,in1-differential
+- realtek,in2-differential
+- realtek,in3-differential
+- realtek,in4-differential
+  Boolean. Indicate MIC1/2/3/4 input are differential, rather than single-ended.
+
+- realtek,dmic1-data-pin
+  0: dmic1 is not used
+  1: using GPIO4 pin as dmic1 data pin
+  2: using IN2N pin as dmic2 data pin
+
+- realtek,dmic2-data-pin
+  0: dmic2 is not used
+  1: using GPIO5 pin as dmic2 data pin
+  2: using IN2P pin as dmic2 data pin
+
+- realtek,jd-src
+  0: No JD is used
+  1: using JD1 as JD source
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+
+Pins on the device (for linking into audio routes) for RT5659/RT5658:
+
+  * DMIC L1
+  * DMIC R1
+  * DMIC L2
+  * DMIC R2
+  * IN1P
+  * IN1N
+  * IN2P
+  * IN2N
+  * IN3P
+  * IN3N
+  * IN4P
+  * IN4N
+  * HPOL
+  * HPOR
+  * LOUTL
+  * LOUTR
+  * MONOOUT
+  * PDML
+  * PDMR
+
+Example:
+
+rt5659 {
+       compatible = "realtek,rt5665";
+       reg = <0x1b>;
+       interrupt-parent = <&gpio>;
+       interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+       realtek,ldo1-en-gpios =
+               <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/timer/jcore,pit.txt b/Documentation/devicetree/bindings/timer/jcore,pit.txt
new file mode 100644 (file)
index 0000000..af5dd35
--- /dev/null
@@ -0,0 +1,24 @@
+J-Core Programmable Interval Timer and Clocksource
+
+Required properties:
+
+- compatible: Must be "jcore,pit".
+
+- reg: Memory region(s) for timer/clocksource registers. For SMP,
+  there should be one region per cpu, indexed by the sequential,
+  zero-based hardware cpu number.
+
+- interrupts: An interrupt to assign for the timer. The actual pit
+  core is integrated with the aic and allows the timer interrupt
+  assignment to be programmed by software, but this property is
+  required in order to reserve an interrupt number that doesn't
+  conflict with other devices.
+
+
+Example:
+
+timer@200 {
+       compatible = "jcore,pit";
+       reg = < 0x200 0x30 0x500 0x30 >;
+       interrupts = < 0x48 >;
+};
index 455f2c310a1b90ce94a087e1983a7e8d5ee869ab..2c30a5479069b98ef22467fd91a0f090c87f1d91 100644 (file)
@@ -28,10 +28,7 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
 - g-use-dma: enable dma usage in gadget driver.
 - g-rx-fifo-size: size of rx fifo size in gadget mode.
 - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
-
-Deprecated properties:
-- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0)
-  in gadget mode.
+- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
 
 Example:
 
index 14cdc101d165d94bb6114763989322ac1958848c..1b5f15653b1bb82ca0fc7801fe01fe8c4c75047a 100644 (file)
@@ -447,7 +447,6 @@ prototypes:
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
        int (*fsync) (struct file *, loff_t start, loff_t end, int datasync);
-       int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,
index 219ffd41a9117d1f598f97ba2745e22a371dfc29..74329fd0add2237a848a72fb71a46d5e4e98cee4 100644 (file)
@@ -395,32 +395,6 @@ is not associated with a file:
 
  or if empty, the mapping is anonymous.
 
-The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
-of the individual tasks of a process. In this file you will see a mapping marked
-as [stack] if that task sees it as a stack. Hence, for the example above, the
-task-level map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
-
-08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
-08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
-0804a000-0806b000 rw-p 00000000 00:00 0          [heap]
-a7cb1000-a7cb2000 ---p 00000000 00:00 0
-a7cb2000-a7eb2000 rw-p 00000000 00:00 0
-a7eb2000-a7eb3000 ---p 00000000 00:00 0
-a7eb3000-a7ed5000 rw-p 00000000 00:00 0          [stack]
-a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
-a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
-a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
-a800b000-a800e000 rw-p 00000000 00:00 0
-a800e000-a8022000 r-xp 00000000 03:00 14462      /lib/libpthread.so.0
-a8022000-a8023000 r--p 00013000 03:00 14462      /lib/libpthread.so.0
-a8023000-a8024000 rw-p 00014000 03:00 14462      /lib/libpthread.so.0
-a8024000-a8027000 rw-p 00000000 00:00 0
-a8027000-a8043000 r-xp 00000000 03:00 8317       /lib/ld-linux.so.2
-a8043000-a8044000 r--p 0001b000 03:00 8317       /lib/ld-linux.so.2
-a8044000-a8045000 rw-p 0001c000 03:00 8317       /lib/ld-linux.so.2
-aff35000-aff4a000 rw-p 00000000 00:00 0
-ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
-
 The /proc/PID/smaps is an extension based on maps, showing the memory
 consumption for each of the process's mappings. For each of mappings there
 is a series of lines such as the following:
index d619c8d71966e255474b3bce54f2b277dd1b337d..b5039a00caafae44660514da3829994436a35e84 100644 (file)
@@ -828,7 +828,6 @@ struct file_operations {
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
        int (*fsync) (struct file *, loff_t, loff_t, int datasync);
-       int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
index 40884c4fe40c5f85c4f64e096b7469141652a8cd..a0f61898d493b720fbc014554b628f5b6e25a93f 100644 (file)
@@ -6,7 +6,7 @@ Note that it only applies to the new descriptor-based interface. For a
 description of the deprecated integer-based GPIO interface please refer to
 gpio-legacy.txt (actually, there is no real mapping possible with the old
 interface; you just fetch an integer from somewhere and request the
-corresponding GPIO.
+corresponding GPIO).
 
 All platforms can enable the GPIO library, but if the platform strictly
 requires GPIO functionality to be present, it needs to select GPIOLIB from its
@@ -162,6 +162,9 @@ The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
 
 Since the "led" GPIOs are mapped as active-high, this example will switch their
 signals to 1, i.e. enabling the LEDs. And for the "power" GPIO, which is mapped
-as active-low, its actual signal will be 0 after this code. Contrary to the legacy
-integer GPIO interface, the active-low property is handled during mapping and is
-thus transparent to GPIO consumers.
+as active-low, its actual signal will be 0 after this code. Contrary to the
+legacy integer GPIO interface, the active-low property is handled during
+mapping and is thus transparent to GPIO consumers.
+
+A set of functions such as gpiod_set_value() is available to work with
+the new descriptor-oriented interface.
index e0aefeece551b52b5d1208a80123ad7c6668f47c..1a014fede0b72b442dbc04a93a184e1bdf5fe324 100644 (file)
@@ -326,7 +326,7 @@ Two parent-locked sibling muxes
 
 This is a good topology.
 
-                                   .--------.
+                                    .--------.
                    .----------.  .--| dev D1 |
                    |  parent- |--'  '--------'
                 .--|  locked  |     .--------.
@@ -350,7 +350,7 @@ Mux-locked and parent-locked sibling muxes
 
 This is a good topology.
 
-                                   .--------.
+                                    .--------.
                    .----------.  .--| dev D1 |
                    |   mux-   |--'  '--------'
                 .--|  locked  |     .--------.
index 6d6c07cf1a9aed11628ac9824c65b84332a30896..63912ef346069b228b984c2f2d1a70f0c9c6ffc0 100644 (file)
@@ -67,13 +67,14 @@ Note that DSA does not currently create network interfaces for the "cpu" and
 Switch tagging protocols
 ------------------------
 
-DSA currently supports 4 different tagging protocols, and a tag-less mode as
+DSA currently supports 5 different tagging protocols, and a tag-less mode as
 well. The different protocols are implemented in:
 
 net/dsa/tag_trailer.c: Marvell's 4 trailer tag mode (legacy)
 net/dsa/tag_dsa.c: Marvell's original DSA tag
 net/dsa/tag_edsa.c: Marvell's enhanced DSA tag
 net/dsa/tag_brcm.c: Broadcom's 4 bytes tag
+net/dsa/tag_qca.c: Qualcomm's 2 bytes tag
 
 The exact format of the tag protocol is vendor specific, but in general, they
 all contain something which:
index 0fe1c6e0dbcd58fccdcc953477da11e2d6598358..a20b2fae942b29e21fba5935f47777b391ecd65f 100644 (file)
@@ -29,8 +29,8 @@ A: There are always two trees (git repositories) in play.  Both are driven
    Linus, and net-next is where the new code goes for the future release.
    You can find the trees here:
 
-       http://git.kernel.org/?p=linux/kernel/git/davem/net.git
-       http://git.kernel.org/?p=linux/kernel/git/davem/net-next.git
+        https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+        https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
 
 Q: How often do changes from these trees make it to the mainline Linus tree?
 
@@ -76,7 +76,7 @@ Q: So where are we now in this cycle?
 
 A: Load the mainline (Linus) page here:
 
-       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git
+       https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
 
    and note the top of the "tags" section.  If it is rc1, it is early
    in the dev cycle.  If it was tagged rc7 a week ago, then a release
@@ -123,7 +123,7 @@ A: Normally Greg Kroah-Hartman collects stable commits himself, but
 
    It contains the patches which Dave has selected, but not yet handed
    off to Greg.  If Greg already has the patch, then it will be here:
-       http://git.kernel.org/cgit/linux/kernel/git/stable/stable-queue.git
+       https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git
 
    A quick way to find whether the patch is in this stable-queue is
    to simply clone the repo, and then git grep the mainline commit ID, e.g.
index 4fb51d32fccc2acd4ebaa1347dcf51fb49cab90d..433b6724797ad7e9476f041c7f0e2dcd77ca8579 100644 (file)
@@ -33,24 +33,6 @@ nf_conntrack_events - BOOLEAN
        If this option is enabled, the connection tracking code will
        provide userspace with connection tracking events via ctnetlink.
 
-nf_conntrack_events_retry_timeout - INTEGER (seconds)
-       default 15
-
-       This option is only relevant when "reliable connection tracking
-       events" are used.  Normally, ctnetlink is "lossy", that is,
-       events are normally dropped when userspace listeners can't keep up.
-
-       Userspace can request "reliable event mode".  When this mode is
-       active, the conntrack will only be destroyed after the event was
-       delivered.  If event delivery fails, the kernel periodically
-       re-tries to send the event to userspace.
-
-       This is the maximum interval the kernel should use when re-trying
-       to deliver the destroy event.
-
-       A higher number means there will be fewer delivery retries and it
-       will take longer for a backlog to be processed.
-
 nf_conntrack_expect_max - INTEGER
        Maximum size of expectation table.  Default value is
        nf_conntrack_buckets / 256. Minimum is 1.
@@ -80,10 +62,13 @@ nf_conntrack_generic_timeout - INTEGER (seconds)
        protocols.
 
 nf_conntrack_helper - BOOLEAN
-       0 - disabled
-       not 0 - enabled (default)
+       0 - disabled (default)
+       not 0 - enabled
 
        Enable automatic conntrack helper assignment.
+       If disabled it is required to set up iptables rules to assign
+       helpers to connections.  See the CT target description in the
+       iptables-extensions(8) man page for further information.
 
 nf_conntrack_icmp_timeout - INTEGER (seconds)
        default 30
diff --git a/Documentation/sound/alsa/soc/codec_to_codec.txt b/Documentation/sound/alsa/soc/codec_to_codec.txt
new file mode 100644 (file)
index 0000000..704a648
--- /dev/null
@@ -0,0 +1,103 @@
+Creating codec to codec dai link for ALSA dapm
+===================================================
+
+Mostly the flow of audio is always from CPU to codec so your system
+will look as below:
+
+ ---------          ---------
+|         |  dai   |         |
+    CPU    ------->    codec
+|         |        |         |
+ ---------          ---------
+
+In case your system looks as below:
+                     ---------
+                    |         |
+                      codec-2
+                    |         |
+                     ---------
+                         |
+                       dai-2
+                         |
+ ----------          ---------
+|          |  dai-1 |         |
+    CPU     ------->  codec-1
+|          |        |         |
+ ----------          ---------
+                         |
+                       dai-3
+                         |
+                     ---------
+                    |         |
+                      codec-3
+                    |         |
+                     ---------
+
+Suppose codec-2 is a bluetooth chip and codec-3 is connected to
+a speaker and you have a below scenario:
+codec-2 will receive the audio data and the user wants to play that
+audio through codec-3 without involving the CPU.This
+aforementioned case is the ideal case when codec to codec
+connection should be used.
+
+Your dai_link should appear as below in your machine
+file:
+
+/*
+ * this pcm stream only supports 24 bit, 2 channel and
+ * 48k sampling rate.
+ */
+static const struct snd_soc_pcm_stream dsp_codec_params = {
+        .formats = SNDRV_PCM_FMTBIT_S24_LE,
+        .rate_min = 48000,
+        .rate_max = 48000,
+        .channels_min = 2,
+        .channels_max = 2,
+};
+
+{
+    .name = "CPU-DSP",
+    .stream_name = "CPU-DSP",
+    .cpu_dai_name = "samsung-i2s.0",
+    .codec_name = "codec-2,
+    .codec_dai_name = "codec-2-dai_name",
+    .platform_name = "samsung-i2s.0",
+    .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+            | SND_SOC_DAIFMT_CBM_CFM,
+    .ignore_suspend = 1,
+    .params = &dsp_codec_params,
+},
+{
+    .name = "DSP-CODEC",
+    .stream_name = "DSP-CODEC",
+    .cpu_dai_name = "wm0010-sdi2",
+    .codec_name = "codec-3,
+    .codec_dai_name = "codec-3-dai_name",
+    .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+            | SND_SOC_DAIFMT_CBM_CFM,
+    .ignore_suspend = 1,
+    .params = &dsp_codec_params,
+},
+
+Above code snippet is motivated from sound/soc/samsung/speyside.c.
+
+Note the "params" callback which lets the dapm know that this
+dai_link is a codec to codec connection.
+
+In dapm core a route is created between cpu_dai playback widget
+and codec_dai capture widget for playback path and vice-versa is
+true for capture path. In order for this aforementioned route to get
+triggered, DAPM needs to find a valid endpoint which could be either
+a sink or source widget corresponding to playback and capture path
+respectively.
+
+In order to trigger this dai_link widget, a thin codec driver for
+the speaker amp can be created as demonstrated in wm8727.c file, it
+sets appropriate constraints for the device even if it needs no control.
+
+Make sure to name your corresponding cpu and codec playback and capture
+dai names ending with "Playback" and "Capture" respectively as dapm core
+will link and power those dais based on the name.
+
+Note that in current device tree there is no way to mark a dai_link
+as codec to codec. However, it may change in future.
index 739db9ab16b2c973b8a348dcbe657a0c9004e227..6bbceb9a3a19d5ce30734493e3c8785a04c1b00d 100644 (file)
@@ -777,6 +777,17 @@ Gets the current timestamp of kvmclock as seen by the current guest. In
 conjunction with KVM_SET_CLOCK, it is used to ensure monotonicity on scenarios
 such as migration.
 
+When KVM_CAP_ADJUST_CLOCK is passed to KVM_CHECK_EXTENSION, it returns the
+set of bits that KVM can return in struct kvm_clock_data's flag member.
+
+The only flag defined now is KVM_CLOCK_TSC_STABLE.  If set, the returned
+value is the exact kvmclock value seen by all VCPUs at the instant
+when KVM_GET_CLOCK was called.  If clear, the returned value is simply
+CLOCK_MONOTONIC plus a constant offset; the offset can be modified
+with KVM_SET_CLOCK.  KVM will try to make all VCPUs follow this clock,
+but the exact value read by each VCPU could differ, because the host
+TSC is not stable.
+
 struct kvm_clock_data {
        __u64 clock;  /* kvmclock current value */
        __u32 flags;
index f2491a8c68b4a6f20c8a2903c21fe7286c7e9e48..e5dd9f4d61008ad6431e067b900608788e573020 100644 (file)
@@ -4,7 +4,17 @@ KVM Lock Overview
 1. Acquisition Orders
 ---------------------
 
-(to be written)
+The acquisition orders for mutexes are as follows:
+
+- kvm->lock is taken outside vcpu->mutex
+
+- kvm->lock is taken outside kvm->slots_lock and kvm->irq_lock
+
+- kvm->slots_lock is taken outside kvm->irq_lock, though acquiring
+  them together is quite rare.
+
+For spinlocks, kvm_lock is taken outside kvm->mmu_lock.  Everything
+else is a leaf: no other lock is taken inside the critical sections.
 
 2: Exception
 ------------
index 1cd38a7e0064e537a95a9fc7473d28cfdb1822f4..e90590a4cbe21556d58f419016ce2405ea51de6b 100644 (file)
@@ -77,6 +77,7 @@ Descriptions of section entries:
        Q: Patchwork web based patch tracking system site
        T: SCM tree type and location.
           Type is one of: git, hg, quilt, stgit, topgit
+       B: Bug tracking system location.
        S: Status, one of the following:
           Supported:   Someone is actually paid to look after this.
           Maintained:  Someone actually looks after it.
@@ -281,6 +282,7 @@ L:  linux-acpi@vger.kernel.org
 W:     https://01.org/linux-acpi
 Q:     https://patchwork.kernel.org/project/linux-acpi/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
+B:     https://bugzilla.kernel.org
 S:     Supported
 F:     drivers/acpi/
 F:     drivers/pnp/pnpacpi/
@@ -304,6 +306,8 @@ W:  https://acpica.org/
 W:     https://github.com/acpica/acpica/
 Q:     https://patchwork.kernel.org/project/linux-acpi/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
+B:     https://bugzilla.kernel.org
+B:     https://bugs.acpica.org
 S:     Supported
 F:     drivers/acpi/acpica/
 F:     include/acpi/
@@ -313,6 +317,7 @@ ACPI FAN DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
 W:     https://01.org/linux-acpi
+B:     https://bugzilla.kernel.org
 S:     Supported
 F:     drivers/acpi/fan.c
 
@@ -328,6 +333,7 @@ ACPI THERMAL DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
 W:     https://01.org/linux-acpi
+B:     https://bugzilla.kernel.org
 S:     Supported
 F:     drivers/acpi/*thermal*
 
@@ -335,6 +341,7 @@ ACPI VIDEO DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
 W:     https://01.org/linux-acpi
+B:     https://bugzilla.kernel.org
 S:     Supported
 F:     drivers/acpi/acpi_video.c
 
@@ -1442,6 +1449,7 @@ F:        drivers/cpufreq/mvebu-cpufreq.c
 F:     arch/arm/configs/mvebu_*_defconfig
 
 ARM/Marvell Berlin SoC support
+M:     Jisheng Zhang <jszhang@marvell.com>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -2317,6 +2325,13 @@ F:       include/uapi/linux/ax25.h
 F:     include/net/ax25.h
 F:     net/ax25/
 
+AXENTIA ASOC DRIVERS
+M:     Peter Rosin <peda@axentia.se>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/axentia,*
+F:     sound/soc/atmel/tse850-pcm5142.c
+
 AZ6007 DVB DRIVER
 M:     Mauro Carvalho Chehab <mchehab@s-opensource.com>
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
@@ -2551,15 +2566,18 @@ S:      Supported
 F:     drivers/net/ethernet/broadcom/genet/
 
 BROADCOM BNX2 GIGABIT ETHERNET DRIVER
-M:     Sony Chacko <sony.chacko@qlogic.com>
-M:     Dept-HSGLinuxNICDev@qlogic.com
+M:     Rasesh Mody <rasesh.mody@cavium.com>
+M:     Harish Patil <harish.patil@cavium.com>
+M:     Dept-GELinuxNICDev@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/broadcom/bnx2.*
 F:     drivers/net/ethernet/broadcom/bnx2_*
 
 BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
-M:     Ariel Elior <ariel.elior@qlogic.com>
+M:     Yuval Mintz <Yuval.Mintz@cavium.com>
+M:     Ariel Elior <ariel.elior@cavium.com>
+M:     everest-linux-l2@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/broadcom/bnx2x/
@@ -2766,7 +2784,9 @@ S:        Supported
 F:     drivers/scsi/bfa/
 
 BROCADE BNA 10 GIGABIT ETHERNET DRIVER
-M:     Rasesh Mody <rasesh.mody@qlogic.com>
+M:     Rasesh Mody <rasesh.mody@cavium.com>
+M:     Sudarsana Kalluru <sudarsana.kalluru@cavium.com>
+M:     Dept-GELinuxNICDev@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/brocade/bna/
@@ -4620,8 +4640,9 @@ F:        sound/usb/misc/ua101.c
 
 EXTENSIBLE FIRMWARE INTERFACE (EFI)
 M:     Matt Fleming <matt@codeblueprint.co.uk>
+M:     Ard Biesheuvel <ard.biesheuvel@linaro.org>
 L:     linux-efi@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
 S:     Maintained
 F:     Documentation/efi-stub.txt
 F:     arch/ia64/kernel/efi.c
@@ -5286,6 +5307,12 @@ M:       Joe Perches <joe@perches.com>
 S:     Maintained
 F:     scripts/get_maintainer.pl
 
+GENWQE (IBM Generic Workqueue Card)
+M:     Frank Haverkamp <haver@linux.vnet.ibm.com>
+M:     Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com>
+S:     Supported
+F:     drivers/misc/genwqe/
+
 GFS2 FILE SYSTEM
 M:     Steven Whitehouse <swhiteho@redhat.com>
 M:     Bob Peterson <rpeterso@redhat.com>
@@ -5650,6 +5677,7 @@ HIBERNATION (aka Software Suspend, aka swsusp)
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-pm@vger.kernel.org
+B:     https://bugzilla.kernel.org
 S:     Supported
 F:     arch/x86/power/
 F:     drivers/base/power/
@@ -7071,6 +7099,7 @@ F:        drivers/scsi/53c700*
 LED SUBSYSTEM
 M:     Richard Purdie <rpurdie@rpsys.net>
 M:     Jacek Anaszewski <j.anaszewski@samsung.com>
+M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-leds@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git
 S:     Maintained
@@ -7912,6 +7941,10 @@ F:       mm/
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Brian Norris <computersforpeace@gmail.com>
+M:     Boris Brezillon <boris.brezillon@free-electrons.com>
+M:     Marek Vasut <marek.vasut@gmail.com>
+M:     Richard Weinberger <richard@nod.at>
+M:     Cyrille Pitchen <cyrille.pitchen@atmel.com>
 L:     linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
@@ -8040,6 +8073,7 @@ F:        drivers/infiniband/hw/mlx4/
 F:     include/linux/mlx4/
 
 MELLANOX MLX5 core VPI driver
+M:     Saeed Mahameed <saeedm@mellanox.com>
 M:     Matan Barak <matanb@mellanox.com>
 M:     Leon Romanovsky <leonro@mellanox.com>
 L:     netdev@vger.kernel.org
@@ -8099,6 +8133,7 @@ S:        Maintained
 F:     drivers/media/dvb-frontends/mn88473*
 
 MODULE SUPPORT
+M:     Jessica Yu <jeyu@redhat.com>
 M:     Rusty Russell <rusty@rustcorp.com.au>
 S:     Maintained
 F:     include/linux/module.h
@@ -8212,7 +8247,7 @@ F:        include/linux/mfd/
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
-T:     git git://git.linaro.org/people/ulf.hansson/mmc.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
 S:     Maintained
 F:     Documentation/devicetree/bindings/mmc/
 F:     drivers/mmc/
@@ -8508,11 +8543,10 @@ F:      Documentation/devicetree/bindings/net/wireless/
 F:     drivers/net/wireless/
 
 NETXEN (1/10) GbE SUPPORT
-M:     Manish Chopra <manish.chopra@qlogic.com>
-M:     Sony Chacko <sony.chacko@qlogic.com>
-M:     Rajesh Borundia <rajesh.borundia@qlogic.com>
+M:     Manish Chopra <manish.chopra@cavium.com>
+M:     Rahul Verma <rahul.verma@cavium.com>
+M:     Dept-GELinuxNICDev@cavium.com
 L:     netdev@vger.kernel.org
-W:     http://www.qlogic.com
 S:     Supported
 F:     drivers/net/ethernet/qlogic/netxen/
 
@@ -9230,11 +9264,12 @@ S:      Maintained
 F:     drivers/pci/host/*layerscape*
 
 PCI DRIVER FOR IMX6
-M:     Richard Zhu <Richard.Zhu@freescale.com>
+M:     Richard Zhu <hongxing.zhu@nxp.com>
 M:     Lucas Stach <l.stach@pengutronix.de>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+F:     Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
 F:     drivers/pci/host/*imx6*
 
 PCI DRIVER FOR TI KEYSTONE
@@ -9293,17 +9328,11 @@ F:      drivers/pci/host/pci-exynos.c
 
 PCI DRIVER FOR SYNOPSIS DESIGNWARE
 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*
-
-PCI DRIVER FOR SYNOPSYS PROTOTYPING DEVICE
-M:     Joao Pinto <jpinto@synopsys.com>
+M:     Joao Pinto <Joao.Pinto@synopsys.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/pci/designware-pcie.txt
-F:     drivers/pci/host/pcie-designware-plat.c
+F:     drivers/pci/host/*designware*
 
 PCI DRIVER FOR GENERIC OF HOSTS
 M:     Will Deacon <will.deacon@arm.com>
@@ -9318,7 +9347,7 @@ PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
 M:     Keith Busch <keith.busch@intel.com>
 L:     linux-pci@vger.kernel.org
 S:     Supported
-F:     arch/x86/pci/vmd.c
+F:     drivers/pci/host/vmd.c
 
 PCIE DRIVER FOR ST SPEAR13XX
 M:     Pratyush Anand <pratyush.anand@gmail.com>
@@ -9605,6 +9634,7 @@ POWER MANAGEMENT CORE
 M:     "Rafael J. Wysocki" <rjw@rjwysocki.net>
 L:     linux-pm@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
+B:     https://bugzilla.kernel.org
 S:     Supported
 F:     drivers/base/power/
 F:     include/linux/pm.h
@@ -9888,33 +9918,32 @@ F:      Documentation/scsi/LICENSE.qla4xxx
 F:     drivers/scsi/qla4xxx/
 
 QLOGIC QLA3XXX NETWORK DRIVER
-M:     Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
-M:     Ron Mercer <ron.mercer@qlogic.com>
-M:     linux-driver@qlogic.com
+M:     Dept-GELinuxNICDev@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     Documentation/networking/LICENSE.qla3xxx
 F:     drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
-M:     Dept-GELinuxNICDev@qlogic.com
+M:     Harish Patil <harish.patil@cavium.com>
+M:     Manish Chopra <manish.chopra@cavium.com>
+M:     Dept-GELinuxNICDev@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qlcnic/
 
 QLOGIC QLGE 10Gb ETHERNET DRIVER
-M:     Harish Patil <harish.patil@qlogic.com>
-M:     Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
-M:     Dept-GELinuxNICDev@qlogic.com
-M:     linux-driver@qlogic.com
+M:     Harish Patil <harish.patil@cavium.com>
+M:     Manish Chopra <manish.chopra@cavium.com>
+M:     Dept-GELinuxNICDev@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qlge/
 
 QLOGIC QL4xxx ETHERNET DRIVER
-M:     Yuval Mintz <Yuval.Mintz@qlogic.com>
-M:     Ariel Elior <Ariel.Elior@qlogic.com>
-M:     everest-linux-l2@qlogic.com
+M:     Yuval Mintz <Yuval.Mintz@cavium.com>
+M:     Ariel Elior <Ariel.Elior@cavium.com>
+M:     everest-linux-l2@cavium.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qed/
@@ -11392,6 +11421,17 @@ W:     http://www.st.com/spear
 S:     Maintained
 F:     drivers/clk/spear/
 
+SPI NOR SUBSYSTEM
+M:     Cyrille Pitchen <cyrille.pitchen@atmel.com>
+M:     Marek Vasut <marek.vasut@gmail.com>
+L:     linux-mtd@lists.infradead.org
+W:     http://www.linux-mtd.infradead.org/
+Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
+T:     git git://github.com/spi-nor/linux.git
+S:     Maintained
+F:     drivers/mtd/spi-nor/
+F:     include/linux/mtd/spi-nor.h
+
 SPI SUBSYSTEM
 M:     Mark Brown <broonie@kernel.org>
 L:     linux-spi@vger.kernel.org
@@ -11584,6 +11624,7 @@ M:      "Rafael J. Wysocki" <rjw@rjwysocki.net>
 M:     Len Brown <len.brown@intel.com>
 M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-pm@vger.kernel.org
+B:     https://bugzilla.kernel.org
 S:     Supported
 F:     Documentation/power/
 F:     arch/x86/kernel/acpi/
@@ -12771,6 +12812,7 @@ F:      include/uapi/linux/virtio_console.h
 
 VIRTIO CORE, NET AND BLOCK DRIVERS
 M:     "Michael S. Tsirkin" <mst@redhat.com>
+M:     Jason Wang <jasowang@redhat.com>
 L:     virtualization@lists.linux-foundation.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/virtio/
@@ -12801,6 +12843,7 @@ F:      include/uapi/linux/virtio_gpu.h
 
 VIRTIO HOST (VHOST)
 M:     "Michael S. Tsirkin" <mst@redhat.com>
+M:     Jason Wang <jasowang@redhat.com>
 L:     kvm@vger.kernel.org
 L:     virtualization@lists.linux-foundation.org
 L:     netdev@vger.kernel.org
index 512e47a53e9aebf10b144b888b349df5ede5f8d0..b1037774e8e83c86fc93afbd705acf8591c6b4ec 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 4
 PATCHLEVEL = 9
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
-NAME = Psychotic Stoned Sheep
+EXTRAVERSION =
+NAME = Roaring Lionus
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -370,7 +370,7 @@ LDFLAGS_MODULE  =
 CFLAGS_KERNEL  =
 AFLAGS_KERNEL  =
 LDFLAGS_vmlinux =
-CFLAGS_GCOV    = -fprofile-arcs -ftest-coverage -fno-tree-loop-im
+CFLAGS_GCOV    = -fprofile-arcs -ftest-coverage -fno-tree-loop-im -Wno-maybe-uninitialized
 CFLAGS_KCOV    := $(call cc-option,-fsanitize-coverage=trace-pc,)
 
 
@@ -399,11 +399,12 @@ KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                   -fno-strict-aliasing -fno-common \
                   -Werror-implicit-function-declaration \
                   -Wno-format-security \
-                  -std=gnu89
+                  -std=gnu89 $(call cc-option,-fno-PIE)
+
 
 KBUILD_AFLAGS_KERNEL :=
 KBUILD_CFLAGS_KERNEL :=
-KBUILD_AFLAGS   := -D__ASSEMBLY__
+KBUILD_AFLAGS   := -D__ASSEMBLY__ $(call cc-option,-fno-PIE)
 KBUILD_AFLAGS_MODULE  := -DMODULE
 KBUILD_CFLAGS_MODULE  := -DMODULE
 KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
@@ -606,6 +607,13 @@ else
 include/config/auto.conf: ;
 endif # $(dot-config)
 
+# For the kernel to actually contain only the needed exported symbols,
+# we have to build modules as well to determine what those symbols are.
+# (this can be evaluated only once include/config/auto.conf has been included)
+ifdef CONFIG_TRIM_UNUSED_KSYMS
+  KBUILD_MODULES := 1
+endif
+
 # The all: target is the default when no target is given on the
 # command line.
 # This allow a user to issue only 'make' to build a kernel including modules
@@ -620,7 +628,6 @@ ARCH_CFLAGS :=
 include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS  += $(call cc-option,-fno-delete-null-pointer-checks,)
-KBUILD_CFLAGS  += $(call cc-disable-warning,maybe-uninitialized,)
 KBUILD_CFLAGS  += $(call cc-disable-warning,frame-address,)
 
 ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
@@ -629,15 +636,18 @@ KBUILD_CFLAGS     += $(call cc-option,-fdata-sections,)
 endif
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS  += -Os
+KBUILD_CFLAGS  += -Os $(call cc-disable-warning,maybe-uninitialized,)
 else
 ifdef CONFIG_PROFILE_ALL_BRANCHES
-KBUILD_CFLAGS  += -O2
+KBUILD_CFLAGS  += -O2 $(call cc-disable-warning,maybe-uninitialized,)
 else
 KBUILD_CFLAGS   += -O2
 endif
 endif
 
+KBUILD_CFLAGS += $(call cc-ifversion, -lt, 0409, \
+                       $(call cc-disable-warning,maybe-uninitialized,))
+
 # Tell gcc to never replace conditional load with a non-conditional one
 KBUILD_CFLAGS  += $(call cc-option,--param=allow-store-data-races=0)
 
@@ -941,7 +951,7 @@ ifdef CONFIG_GDB_SCRIPTS
 endif
 ifdef CONFIG_TRIM_UNUSED_KSYMS
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \
-         "$(MAKE) KBUILD_MODULES=1 -f $(srctree)/Makefile vmlinux_prereq"
+         "$(MAKE) -f $(srctree)/Makefile vmlinux"
 endif
 
 # standalone target for easier testing
@@ -1016,8 +1026,6 @@ prepare2: prepare3 prepare-compiler-check outputmakefile asm-generic
 prepare1: prepare2 $(version_h) include/generated/utsrelease.h \
                    include/config/auto.conf
        $(cmd_crmodverdir)
-       $(Q)test -e include/generated/autoksyms.h || \
-           touch   include/generated/autoksyms.h
 
 archprepare: archheaders archscripts prepare1 scripts_basic
 
index d9ee81769899fb8652046857d2fa3eaabd1bacc1..940dfb4065910822d42f3d11c02ba2305f25b02a 100644 (file)
@@ -157,14 +157,16 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
 static inline int
 read_int(struct task_struct *task, unsigned long addr, int * data)
 {
-       int copied = access_process_vm(task, addr, data, sizeof(int), 0);
+       int copied = access_process_vm(task, addr, data, sizeof(int),
+                       FOLL_FORCE);
        return (copied == sizeof(int)) ? 0 : -EIO;
 }
 
 static inline int
 write_int(struct task_struct *task, unsigned long addr, int data)
 {
-       int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
+       int copied = access_process_vm(task, addr, &data, sizeof(int),
+                       FOLL_FORCE | FOLL_WRITE);
        return (copied == sizeof(int)) ? 0 : -EIO;
 }
 
@@ -281,7 +283,8 @@ long arch_ptrace(struct task_struct *child, long request,
        /* When I and D space are separate, these will need to be fixed.  */
        case PTRACE_PEEKTEXT: /* read word at location addr. */
        case PTRACE_PEEKDATA:
-               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               copied = access_process_vm(child, addr, &tmp, sizeof(tmp),
+                               FOLL_FORCE);
                ret = -EIO;
                if (copied != sizeof(tmp))
                        break;
index ecd12379e2cdb55bf29626ce0590742875574f3a..bd204bfa29edd52f8e4d43c989ab07024e66ab98 100644 (file)
@@ -41,6 +41,8 @@ config ARC
        select PERF_USE_VMALLOC
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_GENERIC_DMA_COHERENT
+       select HAVE_KERNEL_GZIP
+       select HAVE_KERNEL_LZMA
 
 config MIGHT_HAVE_PCI
        bool
@@ -186,14 +188,6 @@ if SMP
 config ARC_HAS_COH_CACHES
        def_bool n
 
-config ARC_MCIP
-       bool "ARConnect Multicore IP (MCIP) Support "
-       depends on ISA_ARCV2
-       help
-         This IP block enables SMP in ARC-HS38 cores.
-         It provides for cross-core interrupts, multi-core debug
-         hardware semaphores, shared memory,....
-
 config NR_CPUS
        int "Maximum number of CPUs (2-4096)"
        range 2 4096
@@ -211,6 +205,15 @@ config ARC_SMP_HALT_ON_RESET
 
 endif  #SMP
 
+config ARC_MCIP
+       bool "ARConnect Multicore IP (MCIP) Support "
+       depends on ISA_ARCV2
+       default y if SMP
+       help
+         This IP block enables SMP in ARC-HS38 cores.
+         It provides for cross-core interrupts, multi-core debug
+         hardware semaphores, shared memory,....
+
 menuconfig ARC_CACHE
        bool "Enable Cache Support"
        default y
@@ -537,14 +540,6 @@ config ARC_DBG_TLB_PARANOIA
        bool "Paranoia Checks in Low Level TLB Handlers"
        default n
 
-config ARC_DBG_TLB_MISS_COUNT
-       bool "Profile TLB Misses"
-       default n
-       select DEBUG_FS
-       help
-         Counts number of I and D TLB Misses and exports them via Debugfs
-         The counters can be cleared via Debugfs as well
-
 endif
 
 config ARC_UBOOT_SUPPORT
index aa82d13d4213855d299e864b54b64d444a126d73..19cce226d1a830793b54b98fba6f56c6a5a6a88d 100644 (file)
@@ -71,7 +71,9 @@ cflags-$(CONFIG_ARC_DW2_UNWIND)               += -fasynchronous-unwind-tables $(cfi)
 ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
 # Generic build system uses -O2, we want -O3
 # Note: No need to add to cflags-y as that happens anyways
-ARCH_CFLAGS += -O3
+#
+# Disable the false maybe-uninitialized warings gcc spits out at -O3
+ARCH_CFLAGS += -O3 $(call cc-disable-warning,maybe-uninitialized,)
 endif
 
 # small data is default for elf32 tool-chain. If not usable, disable it
index e597cb34c16a832e4d219fd95a688126427b34b3..f94cf151e06ab2e142bbf2b867ae8a2de0e255af 100644 (file)
@@ -14,9 +14,15 @@ UIMAGE_ENTRYADDR   = $(LINUX_START_TEXT)
 
 suffix-y := bin
 suffix-$(CONFIG_KERNEL_GZIP)   := gz
+suffix-$(CONFIG_KERNEL_LZMA)   := lzma
 
-targets += uImage uImage.bin uImage.gz
-extra-y += vmlinux.bin vmlinux.bin.gz
+targets += uImage
+targets += uImage.bin
+targets += uImage.gz
+targets += uImage.lzma
+extra-y += vmlinux.bin
+extra-y += vmlinux.bin.gz
+extra-y += vmlinux.bin.lzma
 
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
@@ -24,12 +30,18 @@ $(obj)/vmlinux.bin: vmlinux FORCE
 $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
        $(call if_changed,gzip)
 
+$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,lzma)
+
 $(obj)/uImage.bin: $(obj)/vmlinux.bin FORCE
        $(call if_changed,uimage,none)
 
 $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz FORCE
        $(call if_changed,uimage,gzip)
 
+$(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma FORCE
+       $(call if_changed,uimage,lzma)
+
 $(obj)/uImage: $(obj)/uImage.$(suffix-y)
        @ln -sf $(notdir $<) $@
        @echo '  Image $@ is ready'
index 6ae2c476ad825aee57fadb1e557b95a0bb082647..53ce226f77a59857615f8fc53fca3ba1c4f09749 100644 (file)
@@ -71,7 +71,7 @@
                        reg-io-width = <4>;
                };
 
-               arcpmu0: pmu {
+               arcpct0: pct {
                        compatible = "snps,arc700-pct";
                };
        };
index ce0ccd20b5bfc821b1e2c96d043b6a6e85c7ada8..5ee96b067c085ce1f061e0aac02732d63d4ecf7e 100644 (file)
@@ -69,7 +69,7 @@
                        };
                };
 
-               arcpmu0: pmu {
+               arcpct0: pct {
                        compatible = "snps,arc700-pct";
                };
        };
index bcf603142a33c08d6a0dbc7a50f47b7c84a20e1a..3c391ba565ed080cfad8b66f4c3395975eec90da 100644 (file)
@@ -83,5 +83,9 @@
                        reg = <0xf0003000 0x44>;
                        interrupts = <7>;
                };
+
+               arcpct0: pct {
+                       compatible = "snps,arc700-pct";
+               };
        };
 };
index 7314f538847bd13cf75ee94689b2612c19045e1a..b0066a749d4c49d8a23e3bd33b4a52789789c913 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="../arc_initramfs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
index 65ab9fbf83f25ab89fd6cf74e7fefb66226b2bf6..ebe9ebb92933302af79f98dae000e8567b86ec6b 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="../../arc_initramfs_hs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
index 3b3990cddbe10bc21eeb485521d08a64c61ca457..4bde43278be6757c5c739bfd58a9f030a80c7568 100644 (file)
@@ -12,6 +12,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
index 98cf20933bbb3232da17fe94fdfe0ad3ddf38379..f6fb3d26557eb7c63b2f77263acfed80f0b45387 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="../arc_initramfs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
index ddf8b96d494e90f4a776cdbea8276c54f0babc13..b9f0fe00044b6c44d62a81a91064583cd9badee3 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/"
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
index ceb90745326e52d85f3ca0a9092962c23b740910..6da71ba253a932275c133e55fe68fd19c7ec4379 100644 (file)
@@ -10,6 +10,7 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_PID_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE="../arc_initramfs_hs/"
+CONFIG_PERF_EVENTS=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
@@ -34,7 +35,6 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
 CONFIG_DEVTMPFS=y
@@ -72,7 +72,6 @@ CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HWMON is not set
 CONFIG_DRM=y
 CONFIG_DRM_ARCPGU=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
index db25c65155cb80a284ab3078f60797f2b25735dc..1bd24ec3e350243de4abd0a45cee201027ccf52a 100644 (file)
 #define STATUS_AE_BIT          5       /* Exception active */
 #define STATUS_DE_BIT          6       /* PC is in delay slot */
 #define STATUS_U_BIT           7       /* User/Kernel mode */
+#define STATUS_Z_BIT            11
 #define STATUS_L_BIT           12      /* Loop inhibit */
 
 /* These masks correspond to the status word(STATUS_32) bits */
 #define STATUS_AE_MASK         (1<<STATUS_AE_BIT)
 #define STATUS_DE_MASK         (1<<STATUS_DE_BIT)
 #define STATUS_U_MASK          (1<<STATUS_U_BIT)
+#define STATUS_Z_MASK          (1<<STATUS_Z_BIT)
 #define STATUS_L_MASK          (1<<STATUS_L_BIT)
 
 /*
@@ -349,10 +351,11 @@ struct cpuinfo_arc {
        struct cpuinfo_arc_bpu bpu;
        struct bcr_identity core;
        struct bcr_isa isa;
+       const char *details, *name;
        unsigned int vec_base;
        struct cpuinfo_arc_ccm iccm, dccm;
        struct {
-               unsigned int swap:1, norm:1, minmax:1, barrel:1, crc:1, pad1:3,
+               unsigned int swap:1, norm:1, minmax:1, barrel:1, crc:1, swape:1, pad1:2,
                             fpu_sp:1, fpu_dp:1, pad2:6,
                             debug:1, ap:1, smart:1, rtt:1, pad3:4,
                             timer0:1, timer1:1, rtc:1, gfrc:1, pad4:4;
index fb781e34f322fdd5aec20e9444bb395f4253c3a9..b3410ff6a62dbcc589ffa411f326d6954c8ba80c 100644 (file)
@@ -53,7 +53,7 @@ extern void arc_cache_init(void);
 extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len);
 extern void read_decode_cache_bcr(void);
 
-extern int ioc_exists;
+extern int ioc_enable;
 extern unsigned long perip_base, perip_end;
 
 #endif /* !__ASSEMBLY__ */
index 08e7e2a16ac176a597ceb21c3b0f399b6ad98ea6..a36e8601114d2ca2970f257f9f8d7e5c03ec08a2 100644 (file)
 static inline void __delay(unsigned long loops)
 {
        __asm__ __volatile__(
-       "       lp  1f  \n"
-       "       nop     \n"
-       "1:             \n"
-       : "+l"(loops));
+       "       mov lp_count, %0        \n"
+       "       lp  1f                  \n"
+       "       nop                     \n"
+       "1:                             \n"
+       : : "r"(loops));
 }
 
 extern void __bad_udelay(void);
index 7096f97a14340f5d54766e21245c7ae779da0e72..aa2d6da9d187be21b1f38ac116f40941bb5dc39d 100644 (file)
@@ -54,7 +54,7 @@ extern int elf_check_arch(const struct elf32_hdr *);
  * the loader.  We need to make sure that it is out of the way of the program
  * that it will "exec", and that there is sufficient room for the brk.
  */
-#define ELF_ET_DYN_BASE                (2 * TASK_SIZE / 3)
+#define ELF_ET_DYN_BASE                (2UL * TASK_SIZE / 3)
 
 /*
  * When the program starts, a1 contains a pointer to a function to be
index 847e3bbe387fc92f9b4433bf7e08fc0b11e3ec70..c8fbe4114badd972a18b37de313f91ab7cffd482 100644 (file)
@@ -55,6 +55,22 @@ struct mcip_cmd {
 #define IDU_M_DISTRI_DEST              0x2
 };
 
+struct mcip_bcr {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+               unsigned int pad3:8,
+                            idu:1, llm:1, num_cores:6,
+                            iocoh:1,  gfrc:1, dbg:1, pad2:1,
+                            msg:1, sem:1, ipi:1, pad:1,
+                            ver:8;
+#else
+               unsigned int ver:8,
+                            pad:1, ipi:1, sem:1, msg:1,
+                            pad2:1, dbg:1, gfrc:1, iocoh:1,
+                            num_cores:6, llm:1, idu:1,
+                            pad3:8;
+#endif
+};
+
 /*
  * MCIP programming model
  *
index 518222bb3f8ef4c551b88e93749bbc2efa6da1a8..6e91d8b339c3616b59d7b389353c477acba8a418 100644 (file)
@@ -18,6 +18,7 @@
 struct mod_arch_specific {
        void *unw_info;
        int unw_sec_idx;
+       const char *secstr;
 };
 #endif
 
index 89eeb372005180802181d860be8f215768701659..e94ca72b974e7c7b31c2d631cb773ab3ad707b8d 100644 (file)
@@ -280,7 +280,7 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
 
 #define pte_page(pte)          pfn_to_page(pte_pfn(pte))
 #define mk_pte(page, prot)     pfn_pte(page_to_pfn(page), prot)
-#define pfn_pte(pfn, prot)     __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pte(pfn, prot)     __pte(__pfn_to_phys(pfn) | pgprot_val(prot))
 
 /* Don't use virt_to_pfn for macros below: could cause truncations for PAE40*/
 #define pte_pfn(pte)           (pte_val(pte) >> PAGE_SHIFT)
index 48b37c693db39d6dd2e73df0671edbb01e3be3fa..cb954cdab07087bc6b49e72c8d117c77b905595c 100644 (file)
@@ -27,11 +27,6 @@ struct id_to_str {
        const char *str;
 };
 
-struct cpuinfo_data {
-       struct id_to_str info;
-       int up_range;
-};
-
 extern int root_mountflags, end_mem;
 
 void setup_processor(void);
@@ -43,5 +38,6 @@ void __init setup_arch_memory(void);
 #define IS_USED_RUN(v)         ((v) ? "" : "(not used) ")
 #define IS_USED_CFG(cfg)       IS_USED_RUN(IS_ENABLED(cfg))
 #define IS_AVAIL2(v, s, cfg)   IS_AVAIL1(v, s), IS_AVAIL1(v, IS_USED_CFG(cfg))
+#define IS_AVAIL3(v, v2, s)    IS_AVAIL1(v, s), IS_AVAIL1(v, IS_DISABLED_RUN(v2))
 
 #endif /* __ASMARC_SETUP_H */
index 89fdd1b0a76ebe672094daa10134204cb96cf925..0861007d9ef33b9dbb19a6d2123c3b5d717d3733 100644 (file)
@@ -37,9 +37,9 @@ extern const char *arc_platform_smp_cpuinfo(void);
  * API expected BY platform smp code (FROM arch smp code)
  *
  * smp_ipi_irq_setup:
- *     Takes @cpu and @irq to which the arch-common ISR is hooked up
+ *     Takes @cpu and @hwirq to which the arch-common ISR is hooked up
  */
-extern int smp_ipi_irq_setup(int cpu, int irq);
+extern int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq);
 
 /*
  * struct plat_smp_ops - SMP callbacks provided by platform to ARC SMP
index e56f9fcc558133277ca03d93461a56da5f02a4b9..772b67ca56e7bacb307fe5f5a944b1318b188b97 100644 (file)
@@ -17,6 +17,7 @@ int sys_clone_wrapper(int, int, int, int, int);
 int sys_cacheflush(uint32_t, uint32_t uint32_t);
 int sys_arc_settls(void *);
 int sys_arc_gettls(void);
+int sys_arc_usr_cmpxchg(int *, int, int);
 
 #include <asm-generic/syscalls.h>
 
index 41fa2ec9e02c7721717e5c513bc9703ebed5bed4..9a34136d84b2c77b45ee3b3b7a739f2d994151d4 100644 (file)
 
 #define NR_syscalls    __NR_syscalls
 
+/* Generic syscall (fs/filesystems.c - lost in asm-generic/unistd.h */
+#define __NR_sysfs             (__NR_arch_specific_syscall + 3)
+
 /* ARC specific syscall */
 #define __NR_cacheflush                (__NR_arch_specific_syscall + 0)
 #define __NR_arc_settls                (__NR_arch_specific_syscall + 1)
 #define __NR_arc_gettls                (__NR_arch_specific_syscall + 2)
+#define __NR_arc_usr_cmpxchg   (__NR_arch_specific_syscall + 4)
 
 __SYSCALL(__NR_cacheflush, sys_cacheflush)
 __SYSCALL(__NR_arc_settls, sys_arc_settls)
 __SYSCALL(__NR_arc_gettls, sys_arc_gettls)
-
-
-/* Generic syscall (fs/filesystems.c - lost in asm-generic/unistd.h */
-#define __NR_sysfs             (__NR_arch_specific_syscall + 3)
+__SYSCALL(__NR_arc_usr_cmpxchg, sys_arc_usr_cmpxchg)
 __SYSCALL(__NR_sysfs, sys_sysfs)
 
 #undef __SYSCALL
index f1e07c2344f84cbd6fb351ad65e9a542fc8f1b4e..3b67f538f1425699219fb2cd481be592ba047731 100644 (file)
@@ -31,6 +31,8 @@ static void __init arc_set_early_base_baud(unsigned long dt_root)
                arc_base_baud = 166666666;      /* Fixed 166.6MHz clk (TB10x) */
        else if (of_flat_dt_is_compatible(dt_root, "snps,arc-sdp"))
                arc_base_baud = 33333333;       /* Fixed 33MHz clk (AXS10x) */
+       else if (of_flat_dt_is_compatible(dt_root, "ezchip,arc-nps"))
+               arc_base_baud = 800000000;      /* Fixed 800MHz clk (NPS) */
        else
                arc_base_baud = 50000000;       /* Fixed default 50MHz */
 }
index 72f9179b1a24663b582b73d0bdc1972ec46befa9..f39142acc89e032627ef88431ac4775e71949ed2 100644 (file)
 #include <asm/mcip.h>
 #include <asm/setup.h>
 
-static char smp_cpuinfo_buf[128];
-static int idu_detected;
-
 static DEFINE_RAW_SPINLOCK(mcip_lock);
 
+#ifdef CONFIG_SMP
+
+static char smp_cpuinfo_buf[128];
+
 static void mcip_setup_per_cpu(int cpu)
 {
        smp_ipi_irq_setup(cpu, IPI_IRQ);
@@ -86,21 +87,7 @@ static void mcip_ipi_clear(int irq)
 
 static void mcip_probe_n_setup(void)
 {
-       struct mcip_bcr {
-#ifdef CONFIG_CPU_BIG_ENDIAN
-               unsigned int pad3:8,
-                            idu:1, llm:1, num_cores:6,
-                            iocoh:1,  gfrc:1, dbg:1, pad2:1,
-                            msg:1, sem:1, ipi:1, pad:1,
-                            ver:8;
-#else
-               unsigned int ver:8,
-                            pad:1, ipi:1, sem:1, msg:1,
-                            pad2:1, dbg:1, gfrc:1, iocoh:1,
-                            num_cores:6, llm:1, idu:1,
-                            pad3:8;
-#endif
-       } mp;
+       struct mcip_bcr mp;
 
        READ_BCR(ARC_REG_MCIP_BCR, mp);
 
@@ -114,7 +101,6 @@ static void mcip_probe_n_setup(void)
                IS_AVAIL1(mp.gfrc, "GFRC"));
 
        cpuinfo_arc700[0].extn.gfrc = mp.gfrc;
-       idu_detected = mp.idu;
 
        if (mp.dbg) {
                __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf);
@@ -130,6 +116,8 @@ struct plat_smp_ops plat_smp_ops = {
        .ipi_clear      = mcip_ipi_clear,
 };
 
+#endif
+
 /***************************************************************************
  * ARCv2 Interrupt Distribution Unit (IDU)
  *
@@ -193,6 +181,8 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
 {
        unsigned long flags;
        cpumask_t online;
+       unsigned int destination_bits;
+       unsigned int distribution_mode;
 
        /* errout if no online cpu per @cpumask */
        if (!cpumask_and(&online, cpumask, cpu_online_mask))
@@ -200,8 +190,15 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
 
        raw_spin_lock_irqsave(&mcip_lock, flags);
 
-       idu_set_dest(data->hwirq, cpumask_bits(&online)[0]);
-       idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR);
+       destination_bits = cpumask_bits(&online)[0];
+       idu_set_dest(data->hwirq, destination_bits);
+
+       if (ffs(destination_bits) == fls(destination_bits))
+               distribution_mode = IDU_M_DISTRI_DEST;
+       else
+               distribution_mode = IDU_M_DISTRI_RR;
+
+       idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, distribution_mode);
 
        raw_spin_unlock_irqrestore(&mcip_lock, flags);
 
@@ -219,16 +216,15 @@ static struct irq_chip idu_irq_chip = {
 
 };
 
-static int idu_first_irq;
+static irq_hw_number_t idu_first_hwirq;
 
 static void idu_cascade_isr(struct irq_desc *desc)
 {
-       struct irq_domain *domain = irq_desc_get_handler_data(desc);
-       unsigned int core_irq = irq_desc_get_irq(desc);
-       unsigned int idu_irq;
+       struct irq_domain *idu_domain = irq_desc_get_handler_data(desc);
+       irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc));
+       irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq;
 
-       idu_irq = core_irq - idu_first_irq;
-       generic_handle_irq(irq_find_mapping(domain, idu_irq));
+       generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq));
 }
 
 static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq)
@@ -294,9 +290,12 @@ idu_of_init(struct device_node *intc, struct device_node *parent)
        struct irq_domain *domain;
        /* Read IDU BCR to confirm nr_irqs */
        int nr_irqs = of_irq_count(intc);
-       int i, irq;
+       int i, virq;
+       struct mcip_bcr mp;
+
+       READ_BCR(ARC_REG_MCIP_BCR, mp);
 
-       if (!idu_detected)
+       if (!mp.idu)
                panic("IDU not detected, but DeviceTree using it");
 
        pr_info("MCIP: IDU referenced from Devicetree %d irqs\n", nr_irqs);
@@ -312,11 +311,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent)
                 * however we need it to get the parent virq and set IDU handler
                 * as first level isr
                 */
-               irq = irq_of_parse_and_map(intc, i);
+               virq = irq_of_parse_and_map(intc, i);
                if (!i)
-                       idu_first_irq = irq;
+                       idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq));
 
-               irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain);
+               irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain);
        }
 
        __mcip_cmd(CMD_IDU_ENABLE, 0);
index 9a2849756022c01c2b3c6da9b7b5a0e371ed2e20..42e964db29677877438f8b9bc8e6225cc5f64174 100644 (file)
@@ -30,17 +30,9 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
                              char *secstr, struct module *mod)
 {
 #ifdef CONFIG_ARC_DW2_UNWIND
-       int i;
-
        mod->arch.unw_sec_idx = 0;
        mod->arch.unw_info = NULL;
-
-       for (i = 1; i < hdr->e_shnum; i++) {
-               if (strcmp(secstr+sechdrs[i].sh_name, ".eh_frame") == 0) {
-                       mod->arch.unw_sec_idx = i;
-                       break;
-               }
-       }
+       mod->arch.secstr = secstr;
 #endif
        return 0;
 }
@@ -59,29 +51,33 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                       unsigned int relsec,     /* sec index for relo sec */
                       struct module *module)
 {
-       int i, n;
+       int i, n, relo_type;
        Elf32_Rela *rel_entry = (void *)sechdrs[relsec].sh_addr;
        Elf32_Sym *sym_entry, *sym_sec;
-       Elf32_Addr relocation;
-       Elf32_Addr location;
-       Elf32_Addr sec_to_patch;
-       int relo_type;
-
-       sec_to_patch = sechdrs[sechdrs[relsec].sh_info].sh_addr;
+       Elf32_Addr relocation, location, tgt_addr;
+       unsigned int tgtsec;
+
+       /*
+        * @relsec has relocations e.g. .rela.init.text
+        * @tgtsec is section to patch e.g. .init.text
+        */
+       tgtsec = sechdrs[relsec].sh_info;
+       tgt_addr = sechdrs[tgtsec].sh_addr;
        sym_sec = (Elf32_Sym *) sechdrs[symindex].sh_addr;
        n = sechdrs[relsec].sh_size / sizeof(*rel_entry);
 
-       pr_debug("\n========== Module Sym reloc ===========================\n");
-       pr_debug("Section to fixup %x\n", sec_to_patch);
+       pr_debug("\nSection to fixup %s @%x\n",
+                module->arch.secstr + sechdrs[tgtsec].sh_name, tgt_addr);
        pr_debug("=========================================================\n");
-       pr_debug("rela->r_off | rela->addend | sym->st_value | ADDR | VALUE\n");
+       pr_debug("r_off\tr_add\tst_value ADDRESS  VALUE\n");
        pr_debug("=========================================================\n");
 
        /* Loop thru entries in relocation section */
        for (i = 0; i < n; i++) {
+               const char *s;
 
                /* This is where to make the change */
-               location = sec_to_patch + rel_entry[i].r_offset;
+               location = tgt_addr + rel_entry[i].r_offset;
 
                /* This is the symbol it is referring to.  Note that all
                   undefined symbols have been resolved.  */
@@ -89,10 +85,15 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
 
                relocation = sym_entry->st_value + rel_entry[i].r_addend;
 
-               pr_debug("\t%x\t\t%x\t\t%x  %x %x [%s]\n",
-                       rel_entry[i].r_offset, rel_entry[i].r_addend,
-                       sym_entry->st_value, location, relocation,
-                       strtab + sym_entry->st_name);
+               if (sym_entry->st_name == 0 && ELF_ST_TYPE (sym_entry->st_info) == STT_SECTION) {
+                       s = module->arch.secstr + sechdrs[sym_entry->st_shndx].sh_name;
+               } else {
+                       s = strtab + sym_entry->st_name;
+               }
+
+               pr_debug("   %x\t%x\t%x %x %x [%s]\n",
+                        rel_entry[i].r_offset, rel_entry[i].r_addend,
+                        sym_entry->st_value, location, relocation, s);
 
                /* This assumes modules are built with -mlong-calls
                 * so any branches/jumps are absolute 32 bit jmps
@@ -111,6 +112,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                        goto relo_err;
 
        }
+
+       if (strcmp(module->arch.secstr+sechdrs[tgtsec].sh_name, ".eh_frame") == 0)
+               module->arch.unw_sec_idx = tgtsec;
+
        return 0;
 
 relo_err:
index be1972bd2729e7a41013d521e9349cd4ac028499..a41a79a4f4feaca96306577077bd4745d6cd8537 100644 (file)
@@ -41,6 +41,41 @@ SYSCALL_DEFINE0(arc_gettls)
        return task_thread_info(current)->thr_ptr;
 }
 
+SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new)
+{
+       struct pt_regs *regs = current_pt_regs();
+       int uval = -EFAULT;
+
+       /*
+        * This is only for old cores lacking LLOCK/SCOND, which by defintion
+        * can't possibly be SMP. Thus doesn't need to be SMP safe.
+        * And this also helps reduce the overhead for serializing in
+        * the UP case
+        */
+       WARN_ON_ONCE(IS_ENABLED(CONFIG_SMP));
+
+       /* Z indicates to userspace if operation succeded */
+       regs->status32 &= ~STATUS_Z_MASK;
+
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+               return -EFAULT;
+
+       preempt_disable();
+
+       if (__get_user(uval, uaddr))
+               goto done;
+
+       if (uval == expected) {
+               if (!__put_user(new, uaddr))
+                       regs->status32 |= STATUS_Z_MASK;
+       }
+
+done:
+       preempt_enable();
+
+       return uval;
+}
+
 void arch_cpu_idle(void)
 {
        /* sleep, but enable all interrupts before committing */
index 3df7f9c72f4271478e1ca26cd90f1d59da475129..0385df77a69738f06a45d45553b1c0d6e0980e30 100644 (file)
@@ -40,6 +40,29 @@ struct task_struct *_current_task[NR_CPUS];  /* For stack switching */
 
 struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
 
+static const struct id_to_str arc_cpu_rel[] = {
+#ifdef CONFIG_ISA_ARCOMPACT
+       { 0x34, "R4.10"},
+       { 0x35, "R4.11"},
+#else
+       { 0x51, "R2.0" },
+       { 0x52, "R2.1" },
+       { 0x53, "R3.0" },
+#endif
+       { 0x00, NULL   }
+};
+
+static const struct id_to_str arc_cpu_nm[] = {
+#ifdef CONFIG_ISA_ARCOMPACT
+       { 0x20, "ARC 600"   },
+       { 0x30, "ARC 770"   },  /* 750 identified seperately */
+#else
+       { 0x40, "ARC EM"  },
+       { 0x50, "ARC HS38"  },
+#endif
+       { 0x00, "Unknown"   }
+};
+
 static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu)
 {
        if (is_isa_arcompact()) {
@@ -92,11 +115,26 @@ static void read_arc_build_cfg_regs(void)
        struct bcr_timer timer;
        struct bcr_generic bcr;
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
+       const struct id_to_str *tbl;
+
        FIX_PTR(cpu);
 
        READ_BCR(AUX_IDENTITY, cpu->core);
        READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa);
 
+       for (tbl = &arc_cpu_rel[0]; tbl->id != 0; tbl++) {
+               if (cpu->core.family == tbl->id) {
+                       cpu->details = tbl->str;
+                       break;
+               }
+       }
+
+       for (tbl = &arc_cpu_nm[0]; tbl->id != 0; tbl++) {
+               if ((cpu->core.family & 0xF0) == tbl->id)
+                       break;
+       }
+       cpu->name = tbl->str;
+
        READ_BCR(ARC_REG_TIMERS_BCR, timer);
        cpu->extn.timer0 = timer.t0;
        cpu->extn.timer1 = timer.t1;
@@ -111,6 +149,9 @@ static void read_arc_build_cfg_regs(void)
        cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0;        /* 1,3 */
        cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0;
        cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */
+       cpu->extn.swape = (cpu->core.family >= 0x34) ? 1 :
+                               IS_ENABLED(CONFIG_ARC_HAS_SWAPE);
+
        READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);
 
        /* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
@@ -160,64 +201,38 @@ static void read_arc_build_cfg_regs(void)
        cpu->extn.rtt = bcr.ver ? 1 : 0;
 
        cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt;
-}
 
-static const struct cpuinfo_data arc_cpu_tbl[] = {
-#ifdef CONFIG_ISA_ARCOMPACT
-       { {0x20, "ARC 600"      }, 0x2F},
-       { {0x30, "ARC 700"      }, 0x33},
-       { {0x34, "ARC 700 R4.10"}, 0x34},
-       { {0x35, "ARC 700 R4.11"}, 0x35},
-#else
-       { {0x50, "ARC HS38 R2.0"}, 0x51},
-       { {0x52, "ARC HS38 R2.1"}, 0x52},
-       { {0x53, "ARC HS38 R3.0"}, 0x53},
-#endif
-       { {0x00, NULL           } }
-};
+       /* some hacks for lack of feature BCR info in old ARC700 cores */
+       if (is_isa_arcompact()) {
+               if (!cpu->isa.ver)      /* ISA BCR absent, use Kconfig info */
+                       cpu->isa.atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
+               else
+                       cpu->isa.atomic = cpu->isa.atomic1;
 
+               cpu->isa.be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
+
+                /* there's no direct way to distinguish 750 vs. 770 */
+               if (unlikely(cpu->core.family < 0x34 || cpu->mmu.ver < 3))
+                       cpu->name = "ARC750";
+       }
+}
 
 static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
 {
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
        struct bcr_identity *core = &cpu->core;
-       const struct cpuinfo_data *tbl;
-       char *isa_nm;
-       int i, be, atomic;
-       int n = 0;
+       int i, n = 0;
 
        FIX_PTR(cpu);
 
-       if (is_isa_arcompact()) {
-               isa_nm = "ARCompact";
-               be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
-
-               atomic = cpu->isa.atomic1;
-               if (!cpu->isa.ver)      /* ISA BCR absent, use Kconfig info */
-                       atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
-       } else {
-               isa_nm = "ARCv2";
-               be = cpu->isa.be;
-               atomic = cpu->isa.atomic;
-       }
-
        n += scnprintf(buf + n, len - n,
                       "\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n",
                       core->family, core->cpu_id, core->chip_id);
 
-       for (tbl = &arc_cpu_tbl[0]; tbl->info.id != 0; tbl++) {
-               if ((core->family >= tbl->info.id) &&
-                   (core->family <= tbl->up_range)) {
-                       n += scnprintf(buf + n, len - n,
-                                      "processor [%d]\t: %s (%s ISA) %s\n",
-                                      cpu_id, tbl->info.str, isa_nm,
-                                      IS_AVAIL1(be, "[Big-Endian]"));
-                       break;
-               }
-       }
-
-       if (tbl->info.id == 0)
-               n += scnprintf(buf + n, len - n, "UNKNOWN ARC Processor\n");
+       n += scnprintf(buf + n, len - n, "processor [%d]\t: %s %s (%s ISA) %s\n",
+                      cpu_id, cpu->name, cpu->details,
+                      is_isa_arcompact() ? "ARCompact" : "ARCv2",
+                      IS_AVAIL1(cpu->isa.be, "[Big-Endian]"));
 
        n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ",
                       IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
@@ -226,7 +241,7 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
                                 CONFIG_ARC_HAS_RTC));
 
        n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s",
-                          IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
+                          IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
                           IS_AVAIL2(cpu->isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64),
                           IS_AVAIL1(cpu->isa.unalign, "unalign (not used)"));
 
@@ -253,7 +268,7 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
                       IS_AVAIL1(cpu->extn.swap, "swap "),
                       IS_AVAIL1(cpu->extn.minmax, "minmax "),
                       IS_AVAIL1(cpu->extn.crc, "crc "),
-                      IS_AVAIL2(1, "swape", CONFIG_ARC_HAS_SWAPE));
+                      IS_AVAIL2(cpu->extn.swape, "swape", CONFIG_ARC_HAS_SWAPE));
 
        if (cpu->bpu.ver)
                n += scnprintf(buf + n, len - n,
@@ -272,9 +287,7 @@ static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
 
        FIX_PTR(cpu);
 
-       n += scnprintf(buf + n, len - n,
-                      "Vector Table\t: %#x\nPeripherals\t: %#lx:%#lx\n",
-                      cpu->vec_base, perip_base, perip_end);
+       n += scnprintf(buf + n, len - n, "Vector Table\t: %#x\n", cpu->vec_base);
 
        if (cpu->extn.fpu_sp || cpu->extn.fpu_dp)
                n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n",
@@ -507,7 +520,7 @@ static void *c_start(struct seq_file *m, loff_t *pos)
         * way to pass it w/o having to kmalloc/free a 2 byte string.
         * Encode cpu-id as 0xFFcccc, which is decoded by show routine.
         */
-       return *pos < num_possible_cpus() ? cpu_to_ptr(*pos) : NULL;
+       return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL;
 }
 
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
index f183cc648851e53d0db2736925cdf466d900946a..88674d972c9d056f33f87205aa77049c11006129 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/atomic.h>
 #include <linux/cpumask.h>
 #include <linux/reboot.h>
+#include <linux/irqdomain.h>
 #include <asm/processor.h>
 #include <asm/setup.h>
 #include <asm/mach_desc.h>
@@ -67,11 +68,13 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        int i;
 
        /*
-        * Initialise the present map, which describes the set of CPUs
-        * actually populated at the present time.
+        * if platform didn't set the present map already, do it now
+        * boot cpu is set to present already by init/main.c
         */
-       for (i = 0; i < max_cpus; i++)
-               set_cpu_present(i, true);
+       if (num_present_cpus() <= 1) {
+               for (i = 0; i < max_cpus; i++)
+                       set_cpu_present(i, true);
+       }
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
@@ -351,20 +354,24 @@ irqreturn_t do_IPI(int irq, void *dev_id)
  */
 static DEFINE_PER_CPU(int, ipi_dev);
 
-int smp_ipi_irq_setup(int cpu, int irq)
+int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq)
 {
        int *dev = per_cpu_ptr(&ipi_dev, cpu);
+       unsigned int virq = irq_find_mapping(NULL, hwirq);
+
+       if (!virq)
+               panic("Cannot find virq for root domain and hwirq=%lu", hwirq);
 
        /* Boot cpu calls request, all call enable */
        if (!cpu) {
                int rc;
 
-               rc = request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev);
+               rc = request_percpu_irq(virq, do_IPI, "IPI Interrupt", dev);
                if (rc)
-                       panic("Percpu IRQ request failed for %d\n", irq);
+                       panic("Percpu IRQ request failed for %u\n", virq);
        }
 
-       enable_percpu_irq(irq, 0);
+       enable_percpu_irq(virq, 0);
 
        return 0;
 }
index f927b8dc6eddf614aecbd03138730badf4f3156c..c10390d1ddb6b32abe8d622870350f7be30c57df 100644 (file)
@@ -152,14 +152,17 @@ static cycle_t arc_read_rtc(struct clocksource *cs)
                cycle_t  full;
        } stamp;
 
-
-       __asm__ __volatile(
-       "1:                                             \n"
-       "       lr              %0, [AUX_RTC_LOW]       \n"
-       "       lr              %1, [AUX_RTC_HIGH]      \n"
-       "       lr              %2, [AUX_RTC_CTRL]      \n"
-       "       bbit0.nt        %2, 31, 1b              \n"
-       : "=r" (stamp.low), "=r" (stamp.high), "=r" (status));
+       /*
+        * hardware has an internal state machine which tracks readout of
+        * low/high and updates the CTRL.status if
+        *  - interrupt/exception taken between the two reads
+        *  - high increments after low has been read
+        */
+       do {
+               stamp.low = read_aux_reg(AUX_RTC_LOW);
+               stamp.high = read_aux_reg(AUX_RTC_HIGH);
+               status = read_aux_reg(AUX_RTC_CTRL);
+       } while (!(status & _BITUL(31)));
 
        return stamp.full;
 }
index 934150e7ac4895ef9e4523fd1ffabbdacce2dd74..82f9bc819f4a2d40f9849d88cc4631fa8f07d7a8 100644 (file)
@@ -237,113 +237,3 @@ void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
        if (!user_mode(regs))
                show_stacktrace(current, regs);
 }
-
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/pagemap.h>
-#include <linux/init.h>
-#include <linux/namei.h>
-#include <linux/debugfs.h>
-
-static struct dentry *test_dentry;
-static struct dentry *test_dir;
-static struct dentry *test_u32_dentry;
-
-static u32 clr_on_read = 1;
-
-#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
-u32 numitlb, numdtlb, num_pte_not_present;
-
-static int fill_display_data(char *kbuf)
-{
-       size_t num = 0;
-       num += sprintf(kbuf + num, "I-TLB Miss %x\n", numitlb);
-       num += sprintf(kbuf + num, "D-TLB Miss %x\n", numdtlb);
-       num += sprintf(kbuf + num, "PTE not present %x\n", num_pte_not_present);
-
-       if (clr_on_read)
-               numitlb = numdtlb = num_pte_not_present = 0;
-
-       return num;
-}
-
-static int tlb_stats_open(struct inode *inode, struct file *file)
-{
-       file->private_data = (void *)__get_free_page(GFP_KERNEL);
-       return 0;
-}
-
-/* called on user read(): display the counters */
-static ssize_t tlb_stats_output(struct file *file,     /* file descriptor */
-                               char __user *user_buf,  /* user buffer */
-                               size_t len,             /* length of buffer */
-                               loff_t *offset)         /* offset in the file */
-{
-       size_t num;
-       char *kbuf = (char *)file->private_data;
-
-       /* All of the data can he shoved in one iteration */
-       if (*offset != 0)
-               return 0;
-
-       num = fill_display_data(kbuf);
-
-       /* simple_read_from_buffer() is helper for copy to user space
-          It copies up to @2 (num) bytes from kernel buffer @4 (kbuf) at offset
-          @3 (offset) into the user space address starting at @1 (user_buf).
-          @5 (len) is max size of user buffer
-        */
-       return simple_read_from_buffer(user_buf, num, offset, kbuf, len);
-}
-
-/* called on user write : clears the counters */
-static ssize_t tlb_stats_clear(struct file *file, const char __user *user_buf,
-                              size_t length, loff_t *offset)
-{
-       numitlb = numdtlb = num_pte_not_present = 0;
-       return length;
-}
-
-static int tlb_stats_close(struct inode *inode, struct file *file)
-{
-       free_page((unsigned long)(file->private_data));
-       return 0;
-}
-
-static const struct file_operations tlb_stats_file_ops = {
-       .read = tlb_stats_output,
-       .write = tlb_stats_clear,
-       .open = tlb_stats_open,
-       .release = tlb_stats_close
-};
-#endif
-
-static int __init arc_debugfs_init(void)
-{
-       test_dir = debugfs_create_dir("arc", NULL);
-
-#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
-       test_dentry = debugfs_create_file("tlb_stats", 0444, test_dir, NULL,
-                                         &tlb_stats_file_ops);
-#endif
-
-       test_u32_dentry =
-           debugfs_create_u32("clr_on_read", 0444, test_dir, &clr_on_read);
-
-       return 0;
-}
-
-module_init(arc_debugfs_init);
-
-static void __exit arc_debugfs_exit(void)
-{
-       debugfs_remove(test_u32_dentry);
-       debugfs_remove(test_dentry);
-       debugfs_remove(test_dir);
-}
-module_exit(arc_debugfs_exit);
-
-#endif
index 97dddbefb86a93fa2f1e05275b6f25db3f283644..50d71695cd4ecbeefd64f28e9f44265195b01d15 100644 (file)
@@ -22,8 +22,8 @@
 #include <asm/setup.h>
 
 static int l2_line_sz;
-int ioc_exists;
-volatile int slc_enable = 1, ioc_enable = 1;
+static int ioc_exists;
+int slc_enable = 1, ioc_enable = 0;
 unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE; /* legacy value for boot */
 unsigned long perip_end = 0xFFFFFFFF; /* legacy value */
 
@@ -53,18 +53,15 @@ char *arc_cache_mumbojumbo(int c, char *buf, int len)
        PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache");
        PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache");
 
-       if (!is_isa_arcv2())
-                return buf;
-
        p = &cpuinfo_arc700[c].slc;
        if (p->ver)
                n += scnprintf(buf + n, len - n,
                               "SLC\t\t: %uK, %uB Line%s\n",
                               p->sz_k, p->line_len, IS_USED_RUN(slc_enable));
 
-       if (ioc_exists)
-               n += scnprintf(buf + n, len - n, "IOC\t\t:%s\n",
-                               IS_DISABLED_RUN(ioc_enable));
+       n += scnprintf(buf + n, len - n, "Peripherals\t: %#lx%s%s\n",
+                      perip_base,
+                      IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency "));
 
        return buf;
 }
@@ -113,8 +110,10 @@ static void read_decode_cache_bcr_arcv2(int cpu)
        }
 
        READ_BCR(ARC_REG_CLUSTER_BCR, cbcr);
-       if (cbcr.c && ioc_enable)
+       if (cbcr.c)
                ioc_exists = 1;
+       else
+               ioc_enable = 0;
 
        /* HS 2.0 didn't have AUX_VOL */
        if (cpuinfo_arc700[cpu].core.family > 0x51) {
@@ -1002,7 +1001,7 @@ void arc_cache_init(void)
                        read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_DISABLE);
        }
 
-       if (is_isa_arcv2() && ioc_exists) {
+       if (is_isa_arcv2() && ioc_enable) {
                /* IO coherency base - 0x8z */
                write_aux_reg(ARC_REG_IO_COH_AP0_BASE, 0x80000);
                /* IO coherency aperture size - 512Mb: 0x8z-0xAz */
index 20afc65e22dc780c69dea280acfc6907a1680e9f..cd8aad8226dd5c151989e1233603d9cb42781bf8 100644 (file)
@@ -45,7 +45,7 @@ static void *arc_dma_alloc(struct device *dev, size_t size,
         *   -For coherent data, Read/Write to buffers terminate early in cache
         *   (vs. always going to memory - thus are faster)
         */
-       if ((is_isa_arcv2() && ioc_exists) ||
+       if ((is_isa_arcv2() && ioc_enable) ||
            (attrs & DMA_ATTR_NON_CONSISTENT))
                need_coh = 0;
 
@@ -97,7 +97,7 @@ static void arc_dma_free(struct device *dev, size_t size, void *vaddr,
        int is_non_coh = 1;
 
        is_non_coh = (attrs & DMA_ATTR_NON_CONSISTENT) ||
-                       (is_isa_arcv2() && ioc_exists);
+                       (is_isa_arcv2() && ioc_enable);
 
        if (PageHighMem(page) || !is_non_coh)
                iounmap((void __force __iomem *)vaddr);
@@ -105,6 +105,31 @@ static void arc_dma_free(struct device *dev, size_t size, void *vaddr,
        __free_pages(page, get_order(size));
 }
 
+static int arc_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+                       void *cpu_addr, dma_addr_t dma_addr, size_t size,
+                       unsigned long attrs)
+{
+       unsigned long user_count = vma_pages(vma);
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       unsigned long pfn = __phys_to_pfn(plat_dma_to_phys(dev, dma_addr));
+       unsigned long off = vma->vm_pgoff;
+       int ret = -ENXIO;
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+               return ret;
+
+       if (off < count && user_count <= (count - off)) {
+               ret = remap_pfn_range(vma, vma->vm_start,
+                                     pfn + off,
+                                     user_count << PAGE_SHIFT,
+                                     vma->vm_page_prot);
+       }
+
+       return ret;
+}
+
 /*
  * streaming DMA Mapping API...
  * CPU accesses page via normal paddr, thus needs to explicitly made
@@ -193,6 +218,7 @@ static int arc_dma_supported(struct device *dev, u64 dma_mask)
 struct dma_map_ops arc_dma_ops = {
        .alloc                  = arc_dma_alloc,
        .free                   = arc_dma_free,
+       .mmap                   = arc_dma_mmap,
        .map_page               = arc_dma_map_page,
        .map_sg                 = arc_dma_map_sg,
        .sync_single_for_device = arc_dma_sync_single_for_device,
index ec868a9081a1103790e594063d1544c0766be3fb..bdb295e09160b2037c9dd90058963800cbe78d08 100644 (file)
@@ -793,16 +793,16 @@ char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len)
        char super_pg[64] = "";
 
        if (p_mmu->s_pg_sz_m)
-               scnprintf(super_pg, 64, "%dM Super Page%s, ",
+               scnprintf(super_pg, 64, "%dM Super Page %s",
                          p_mmu->s_pg_sz_m,
                          IS_USED_CFG(CONFIG_TRANSPARENT_HUGEPAGE));
 
        n += scnprintf(buf + n, len - n,
-                     "MMU [v%x]\t: %dk PAGE, %sJTLB %d (%dx%d), uDTLB %d, uITLB %d %s%s\n",
+                     "MMU [v%x]\t: %dk PAGE, %sJTLB %d (%dx%d), uDTLB %d, uITLB %d%s%s\n",
                       p_mmu->ver, p_mmu->pg_sz_k, super_pg,
                       p_mmu->sets * p_mmu->ways, p_mmu->sets, p_mmu->ways,
                       p_mmu->u_dtlb, p_mmu->u_itlb,
-                      IS_AVAIL2(p_mmu->pae, "PAE40 ", CONFIG_ARC_HAS_PAE40));
+                      IS_AVAIL2(p_mmu->pae, "PAE40 ", CONFIG_ARC_HAS_PAE40));
 
        return buf;
 }
index f1967eeb32e757bb906580fecfce84a309df9983..b30e4e36bb00dd3c5feaa685fe08dd0629404119 100644 (file)
@@ -237,15 +237,6 @@ ex_saved_reg1:
 
 2:
 
-#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
-       and.f 0, r0, _PAGE_PRESENT
-       bz   1f
-       ld   r3, [num_pte_not_present]
-       add  r3, r3, 1
-       st   r3, [num_pte_not_present]
-1:
-#endif
-
 .endm
 
 ;-----------------------------------------------------------------
@@ -309,12 +300,6 @@ ENTRY(EV_TLBMissI)
 
        TLBMISS_FREEUP_REGS
 
-#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
-       ld  r0, [@numitlb]
-       add r0, r0, 1
-       st  r0, [@numitlb]
-#endif
-
        ;----------------------------------------------------------------
        ; Get the PTE corresponding to V-addr accessed, r2 is setup with EFA
        LOAD_FAULT_PTE
@@ -349,12 +334,6 @@ ENTRY(EV_TLBMissD)
 
        TLBMISS_FREEUP_REGS
 
-#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
-       ld  r0, [@numdtlb]
-       add r0, r0, 1
-       st  r0, [@numdtlb]
-#endif
-
        ;----------------------------------------------------------------
        ; Get the PTE corresponding to V-addr accessed
        ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE, r2 = EFA
index 5e901f86e4bd068af0b665bd3d1a3ee3ea6c773d..56a4c8522f111cc5221e2ead6b6574100cd3f685 100644 (file)
@@ -140,16 +140,10 @@ static void eznps_init_per_cpu(int cpu)
        mtm_enable_core(cpu);
 }
 
-static void eznps_ipi_clear(int irq)
-{
-       write_aux_reg(CTOP_AUX_IACK, 1 << irq);
-}
-
 struct plat_smp_ops plat_smp_ops = {
        .info           = smp_cpuinfo_buf,
        .init_early_smp = eznps_init_cpumasks,
        .cpu_kick       = eznps_smp_wakeup_cpu,
        .ipi_send       = eznps_ipi_send,
        .init_per_cpu   = eznps_init_per_cpu,
-       .ipi_clear      = eznps_ipi_clear,
 };
index befcd26199021e4bf61f5e90a508ebdda16e347b..c558ba75cbccf909063e0f4f131f7efdfd28867b 100644 (file)
@@ -745,7 +745,6 @@ dtb-$(CONFIG_MACH_SUN4I) += \
        sun4i-a10-pcduino2.dtb \
        sun4i-a10-pov-protab2-ips9.dtb
 dtb-$(CONFIG_MACH_SUN5I) += \
-       ntc-gr8-evb.dtb \
        sun5i-a10s-auxtek-t003.dtb \
        sun5i-a10s-auxtek-t004.dtb \
        sun5i-a10s-mk802.dtb \
@@ -761,6 +760,7 @@ dtb-$(CONFIG_MACH_SUN5I) += \
        sun5i-a13-olinuxino-micro.dtb \
        sun5i-a13-q8-tablet.dtb \
        sun5i-a13-utoo-p66.dtb \
+       sun5i-gr8-evb.dtb \
        sun5i-r8-chip.dtb
 dtb-$(CONFIG_MACH_SUN6I) += \
        sun6i-a31-app4-evb1.dtb \
index dec4b073ceb138e93a545815f0dce636cf7f6092..379939699164aa6dbd1c90b422496c1ab72edff3 100644 (file)
@@ -64,8 +64,8 @@
                        };
 
                        ldo3_reg: ldo3 {
-                               regulator-min-microvolt = <600000>;
-                               regulator-max-microvolt = <1800000>;
+                               regulator-min-microvolt = <1725000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
 
@@ -76,8 +76,8 @@
                        };
 
                        ldo5_reg: ldo5 {
-                               regulator-min-microvolt = <1725000>;
-                               regulator-max-microvolt = <3300000>;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3600000>;
                                regulator-always-on;
                        };
 
                        };
 
                        ldo9_reg: ldo9 {
-                               regulator-min-microvolt = <1200000>;
+                               regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3600000>;
                                regulator-always-on;
                        };
 
                        ldo10_reg: ldo10 {
-                               regulator-min-microvolt = <1250000>;
-                               regulator-max-microvolt = <3650000>;
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3600000>;
                                regulator-always-on;
                        };
                };
index 0d7d5ac6257b5080f84b855d62f9edc93af74fea..2b6cb05bc01a85f937823d8c1c97fd5aec13bb5c 100644 (file)
                                reg = <0x30730000 0x10000>;
                                interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>,
-                                       <&clks IMX7D_CLK_DUMMY>,
-                                       <&clks IMX7D_CLK_DUMMY>;
-                               clock-names = "pix", "axi", "disp_axi";
+                                       <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>;
+                               clock-names = "pix", "axi";
                                status = "disabled";
                        };
                };
index 0ff1c2de95bfc1a172cd2c7a98e5baf8d93260d1..26cce4d18405d5c993377ed7a246d7c80b43dcea 100644 (file)
                };
        };
 
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0>;
+       };
+
        wl12xx_vmmc: wl12xx_vmmc {
                compatible = "regulator-fixed";
                regulator-name = "vwl1271";
index 731ec37aed5b505b31e95e35319c3e8213e1118a..8f9a69ca818cecb759e71c1b6b97e4073c3e22e4 100644 (file)
@@ -13,9 +13,9 @@
                };
        };
 
-       memory@0 {
+       memory@80000000 {
                device_type = "memory";
-               reg = <0 0>;
+               reg = <0x80000000 0>;
        };
 
        leds {
index 6365635fea5c8dd5e65ac70459a1a6427631fd9a..4caadb25324977e67c40d4ebde2929cd6782cbf8 100644 (file)
                compatible = "ti,abe-twl6040";
                ti,model = "omap5-uevm";
 
+               ti,jack-detection;
                ti,mclk-freq = <19200000>;
 
                ti,mcpdm = <&mcpdm>;
                        ti,backup-battery-charge-high-current;
                };
 
-               gpadc {
+               gpadc: gpadc {
                        compatible = "ti,palmas-gpadc";
                        interrupts = <18 0
                                      16 0
                                smps6_reg: smps6 {
                                        /* VDD_DDR3 - over VDD_SMPS6 */
                                        regulator-name = "smps6";
-                                       regulator-min-microvolt = <1200000>;
-                                       regulator-max-microvolt = <1200000>;
+                                       regulator-min-microvolt = <1350000>;
+                                       regulator-max-microvolt = <1350000>;
                                        regulator-always-on;
                                        regulator-boot-on;
                                };
index 1cf644bfd7ea13afd59f404b4825fefc9b67b2f5..51dc734cd5b902663df96e15dfeba4820966ce05 100644 (file)
        gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
 };
 
+&sata {
+       nr-ports = <2>;
+};
+
 &ehci1 {
        status = "okay";
 };
index b3df1c60d4657e59255f39ff24cccc87a895ca6d..386eee6de2320aa60365095d74378ce11a865f0d 100644 (file)
                        arm,primecell-periphid = <0x10480180>;
                        max-frequency = <100000000>;
                        bus-width = <4>;
+                       cap-sd-highspeed;
                        cap-mmc-highspeed;
+                       sd-uhs-sdr12;
+                       sd-uhs-sdr25;
+                       /* All direction control is used */
+                       st,sig-dir-cmd;
+                       st,sig-dir-dat0;
+                       st,sig-dir-dat2;
+                       st,sig-dir-dat31;
+                       st,sig-pin-fbclk;
+                       full-pwr-cycle;
                        vmmc-supply = <&ab8500_ldo_aux3_reg>;
                        vqmmc-supply = <&vmmci>;
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&sdi0_default_mode>;
                        pinctrl-1 = <&sdi0_sleep_mode>;
 
-                       cd-gpios  = <&gpio6 26 GPIO_ACTIVE_LOW>; // 218
+                       /* GPIO218 MMC_CD */
+                       cd-gpios  = <&gpio6 26 GPIO_ACTIVE_LOW>;
 
                        status = "okay";
                };
                                        /* VMMCI level-shifter enable */
                                        snowball_cfg3 {
                                                pins = "GPIO217_AH12";
-                                               ste,config = <&gpio_out_lo>;
+                                               ste,config = <&gpio_out_hi>;
                                        };
                                        /* VMMCI level-shifter voltage select */
                                        snowball_cfg4 {
index 91096a49efa95af9e63082765d97eac2f81f1210..8f79b4147bba1b5f57155d1a738b7af851a1e901 100644 (file)
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c0_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c1_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c2_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c3_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c4_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c5_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c10_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
                        clock-frequency = <400000>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_i2c11_default>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
                        status = "disabled";
                };
index ef2ff2f518f619a91377238f6d6e28a0baa83aab..7fb507fcba7eed404de64af7d5669de2274e2b99 100644 (file)
@@ -74,7 +74,7 @@
                /* Low speed expansion connector */
                spi0: spi@9844000 {
                        label = "LS-SPI0";
-                       cs-gpio = <&pio30 3 0>;
+                       cs-gpios = <&pio30 3 0>;
                        status = "okay";
                };
 
similarity index 99%
rename from arch/arm/boot/dts/ntc-gr8-evb.dts
rename to arch/arm/boot/dts/sun5i-gr8-evb.dts
index 4b622f3b522047f26c02e4102427c0a50dd0631b..714381fd64d7d4715b02a3964b15cb4d567f6488 100644 (file)
@@ -44,7 +44,7 @@
  */
 
 /dts-v1/;
-#include "ntc-gr8.dtsi"
+#include "sun5i-gr8.dtsi"
 #include "sunxi-common-regulators.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
index 48fc24f36fcb268b7c0ba30348e0f0cc17826a9c..300a1bd5a6ecfd42a8968c7b76d2296fbccc1a2f 100644 (file)
                        uart1_pins_a: uart1@0 {
                                allwinner,pins = "PG6", "PG7";
                                allwinner,function = "uart1";
+                               allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+                               allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
                        };
 
                        uart1_pins_cts_rts_a: uart1-cts-rts@0 {
                                allwinner,pins = "PG8", "PG9";
                                allwinner,function = "uart1";
+                               allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+                               allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
                        };
 
                        mmc0_pins_a: mmc0@0 {
index 75a865406d3ef54c1579b4f558560aaf90567d1c..f4ba088b225edee8d26dcfdf5ab4f8469ea9628d 100644 (file)
                        };
 
                        uart3_pins: uart3 {
-                               allwinner,pins = "PG13", "PG14";
+                               allwinner,pins = "PA13", "PA14";
                                allwinner,function = "uart3";
                                allwinner,drive = <SUN4I_PINCTRL_10_MA>;
                                allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
index 2c49c3614bda53ddbea05c8157009a932623253e..5357ea9c14b1ed59944f137b228ba3c4996910c7 100644 (file)
 };
 
 &mio_clk {
-       compatible = "socionext,uniphier-pro5-mio-clock";
+       compatible = "socionext,uniphier-pro5-sd-clock";
 };
 
 &mio_rst {
-       compatible = "socionext,uniphier-pro5-mio-reset";
+       compatible = "socionext,uniphier-pro5-sd-reset";
 };
 
 &peri_clk {
index 8789cd518933dbaf1564e0e333867fdc4f73d6e4..950f07ba03371ef102289238a48c008a40bb8b86 100644 (file)
 };
 
 &mio_clk {
-       compatible = "socionext,uniphier-pxs2-mio-clock";
+       compatible = "socionext,uniphier-pxs2-sd-clock";
 };
 
 &mio_rst {
-       compatible = "socionext,uniphier-pxs2-mio-reset";
+       compatible = "socionext,uniphier-pxs2-sd-reset";
 };
 
 &peri_clk {
index a3824e61bd72c7cb57ed643519661efe02e0c1fe..d7fdb2a7d97b696458a0ccc892d727fcc2d0f236 100644 (file)
@@ -70,7 +70,7 @@
                        global_timer: timer@40002200 {
                                compatible = "arm,cortex-a9-global-timer";
                                reg = <0x40002200 0x20>;
-                               interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <GIC_PPI 11 IRQ_TYPE_EDGE_RISING>;
                                interrupt-parent = <&intc>;
                                clocks = <&clks VF610_CLK_PLATFORM_BUS>;
                        };
index 437d0740dec604a24dbbcccf8bdbbbb4cc411f85..11f37ed1dbfffbdcc9475bc59ce1743a30b2615a 100644 (file)
@@ -850,6 +850,7 @@ CONFIG_PWM_SUN4I=y
 CONFIG_PWM_TEGRA=y
 CONFIG_PWM_VT8500=y
 CONFIG_PHY_HIX5HD2_SATA=y
+CONFIG_E1000E=y
 CONFIG_PWM_STI=y
 CONFIG_PWM_BCM2835=y
 CONFIG_PWM_BRCMSTB=m
index 0745538b26d3f0f439780ab2a943e4cd47f3ef33..55e0e3ea9cb6bdeb19ff5c47385a571799dd71e6 100644 (file)
@@ -8,7 +8,6 @@ generic-y += early_ioremap.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
-generic-y += export.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
index d7ea6bcb29bf68489323f1c777e057de0b81e364..8ef05381984b1b6ba977035c82607423b37835c0 100644 (file)
@@ -66,6 +66,7 @@ extern char __kvm_hyp_vector[];
 extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
+extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
index 2d19e02d03fd69e75f327659f582d8abbdf909e9..d5423ab15ed5be1c705817e13d4a7d7fe35b465b 100644 (file)
@@ -57,6 +57,9 @@ struct kvm_arch {
        /* VTTBR value associated with below pgd and vmid */
        u64    vttbr;
 
+       /* The last vcpu id that ran on each physical CPU */
+       int __percpu *last_vcpu_ran;
+
        /* Timer */
        struct arch_timer_kvm   timer;
 
index 343135ede5fa01d848ec609f0eafc08f610f5aab..58508900c4bb264be2a874299b829b31a9cb5601 100644 (file)
@@ -71,6 +71,7 @@
 #define ICIALLUIS      __ACCESS_CP15(c7, 0, c1, 0)
 #define ATS1CPR                __ACCESS_CP15(c7, 0, c8, 0)
 #define TLBIALLIS      __ACCESS_CP15(c8, 0, c3, 0)
+#define TLBIALL                __ACCESS_CP15(c8, 0, c7, 0)
 #define TLBIALLNSNHIS  __ACCESS_CP15(c8, 4, c3, 4)
 #define PRRR           __ACCESS_CP15(c10, 0, c2, 0)
 #define NMRR           __ACCESS_CP15(c10, 0, c2, 1)
index 194b6992338920680c14c46326999791e33defa6..ada0d29a660f2fad8bdcf9dbef82affd62e7bf24 100644 (file)
@@ -19,7 +19,7 @@
  * This may need to be greater than __NR_last_syscall+1 in order to
  * account for the padding in the syscall table
  */
-#define __NR_syscalls  (396)
+#define __NR_syscalls  (400)
 
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_GETHOSTNAME
index 2cb9dc770e1d41e8867f949e1ef13e028568a3d3..314100a06ccb6c65161a34aae415c6ed89b060e5 100644 (file)
 #define __NR_copy_file_range           (__NR_SYSCALL_BASE+391)
 #define __NR_preadv2                   (__NR_SYSCALL_BASE+392)
 #define __NR_pwritev2                  (__NR_SYSCALL_BASE+393)
+#define __NR_pkey_mprotect             (__NR_SYSCALL_BASE+394)
+#define __NR_pkey_alloc                        (__NR_SYSCALL_BASE+395)
+#define __NR_pkey_free                 (__NR_SYSCALL_BASE+396)
 
 /*
  * The following SWIs are ARM private.
index 68c2c097cffea17498b61c33cfe6d488dfa67475..ad325a8c7e1e5d1dfbad11e8846169696d36e6bc 100644 (file)
@@ -33,7 +33,7 @@ endif
 obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)      += dma.o
 obj-$(CONFIG_FIQ)              += fiq.o fiqasm.o
-obj-$(CONFIG_MODULES)          += module.o
+obj-$(CONFIG_MODULES)          += armksyms.o module.o
 obj-$(CONFIG_ARM_MODULE_PLTS)  += module-plts.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
 obj-$(CONFIG_PCI)              += bios32.o isa.o
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
new file mode 100644 (file)
index 0000000..7e45f69
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *  linux/arch/arm/kernel/armksyms.c
+ *
+ *  Copyright (C) 2000 Russell King
+ *
+ * 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/export.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/cryptohash.h>
+#include <linux/delay.h>
+#include <linux/in6.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/arm-smccc.h>
+
+#include <asm/checksum.h>
+#include <asm/ftrace.h>
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler...  (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+extern void __ashldi3(void);
+extern void __ashrdi3(void);
+extern void __divsi3(void);
+extern void __lshrdi3(void);
+extern void __modsi3(void);
+extern void __muldi3(void);
+extern void __ucmpdi2(void);
+extern void __udivsi3(void);
+extern void __umodsi3(void);
+extern void __do_div64(void);
+extern void __bswapsi2(void);
+extern void __bswapdi2(void);
+
+extern void __aeabi_idiv(void);
+extern void __aeabi_idivmod(void);
+extern void __aeabi_lasr(void);
+extern void __aeabi_llsl(void);
+extern void __aeabi_llsr(void);
+extern void __aeabi_lmul(void);
+extern void __aeabi_uidiv(void);
+extern void __aeabi_uidivmod(void);
+extern void __aeabi_ulcmp(void);
+
+extern void fpundefinstr(void);
+
+void mmioset(void *, unsigned int, size_t);
+void mmiocpy(void *, const void *, size_t);
+
+       /* platform dependent support */
+EXPORT_SYMBOL(arm_delay_ops);
+
+       /* networking */
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+EXPORT_SYMBOL(__csum_ipv6_magic);
+
+       /* io */
+#ifndef __raw_readsb
+EXPORT_SYMBOL(__raw_readsb);
+#endif
+#ifndef __raw_readsw
+EXPORT_SYMBOL(__raw_readsw);
+#endif
+#ifndef __raw_readsl
+EXPORT_SYMBOL(__raw_readsl);
+#endif
+#ifndef __raw_writesb
+EXPORT_SYMBOL(__raw_writesb);
+#endif
+#ifndef __raw_writesw
+EXPORT_SYMBOL(__raw_writesw);
+#endif
+#ifndef __raw_writesl
+EXPORT_SYMBOL(__raw_writesl);
+#endif
+
+       /* string / mem functions */
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(__memzero);
+
+EXPORT_SYMBOL(mmioset);
+EXPORT_SYMBOL(mmiocpy);
+
+#ifdef CONFIG_MMU
+EXPORT_SYMBOL(copy_page);
+
+EXPORT_SYMBOL(arm_copy_from_user);
+EXPORT_SYMBOL(arm_copy_to_user);
+EXPORT_SYMBOL(arm_clear_user);
+
+EXPORT_SYMBOL(__get_user_1);
+EXPORT_SYMBOL(__get_user_2);
+EXPORT_SYMBOL(__get_user_4);
+EXPORT_SYMBOL(__get_user_8);
+
+#ifdef __ARMEB__
+EXPORT_SYMBOL(__get_user_64t_1);
+EXPORT_SYMBOL(__get_user_64t_2);
+EXPORT_SYMBOL(__get_user_64t_4);
+EXPORT_SYMBOL(__get_user_32t_8);
+#endif
+
+EXPORT_SYMBOL(__put_user_1);
+EXPORT_SYMBOL(__put_user_2);
+EXPORT_SYMBOL(__put_user_4);
+EXPORT_SYMBOL(__put_user_8);
+#endif
+
+       /* gcc lib functions */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__ucmpdi2);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+EXPORT_SYMBOL(__do_div64);
+EXPORT_SYMBOL(__bswapsi2);
+EXPORT_SYMBOL(__bswapdi2);
+
+#ifdef CONFIG_AEABI
+EXPORT_SYMBOL(__aeabi_idiv);
+EXPORT_SYMBOL(__aeabi_idivmod);
+EXPORT_SYMBOL(__aeabi_lasr);
+EXPORT_SYMBOL(__aeabi_llsl);
+EXPORT_SYMBOL(__aeabi_llsr);
+EXPORT_SYMBOL(__aeabi_lmul);
+EXPORT_SYMBOL(__aeabi_uidiv);
+EXPORT_SYMBOL(__aeabi_uidivmod);
+EXPORT_SYMBOL(__aeabi_ulcmp);
+#endif
+
+       /* bitops */
+EXPORT_SYMBOL(_set_bit);
+EXPORT_SYMBOL(_test_and_set_bit);
+EXPORT_SYMBOL(_clear_bit);
+EXPORT_SYMBOL(_test_and_clear_bit);
+EXPORT_SYMBOL(_change_bit);
+EXPORT_SYMBOL(_test_and_change_bit);
+EXPORT_SYMBOL(_find_first_zero_bit_le);
+EXPORT_SYMBOL(_find_next_zero_bit_le);
+EXPORT_SYMBOL(_find_first_bit_le);
+EXPORT_SYMBOL(_find_next_bit_le);
+
+#ifdef __ARMEB__
+EXPORT_SYMBOL(_find_first_zero_bit_be);
+EXPORT_SYMBOL(_find_next_zero_bit_be);
+EXPORT_SYMBOL(_find_first_bit_be);
+EXPORT_SYMBOL(_find_next_bit_be);
+#endif
+
+#ifdef CONFIG_FUNCTION_TRACER
+#ifdef CONFIG_OLD_MCOUNT
+EXPORT_SYMBOL(mcount);
+#endif
+EXPORT_SYMBOL(__gnu_mcount_nc);
+#endif
+
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+EXPORT_SYMBOL(__pv_phys_pfn_offset);
+EXPORT_SYMBOL(__pv_offset);
+#endif
+
+#ifdef CONFIG_HAVE_ARM_SMCCC
+EXPORT_SYMBOL(arm_smccc_smc);
+EXPORT_SYMBOL(arm_smccc_hvc);
+#endif
index 703fa0f3cd8f812907b47ac7c84646ff3e3aff94..08030b18f10a3b73c2bd46ffbfe72ad4b0ffde24 100644 (file)
                CALL(sys_copy_file_range)
                CALL(sys_preadv2)
                CALL(sys_pwritev2)
+               CALL(sys_pkey_mprotect)
+/* 395 */      CALL(sys_pkey_alloc)
+               CALL(sys_pkey_free)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index b629d3f11c3da31af54c09159b581ebe30e390b2..c73c4030ca5dd549e3b102d4a77f493e1549e02d 100644 (file)
@@ -7,7 +7,6 @@
 #include <asm/assembler.h>
 #include <asm/ftrace.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
 #include "entry-header.S"
 
@@ -154,7 +153,6 @@ ENTRY(mcount)
        __mcount _old
 #endif
 ENDPROC(mcount)
-EXPORT_SYMBOL(mcount)
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 ENTRY(ftrace_caller_old)
@@ -207,7 +205,6 @@ UNWIND(.fnstart)
 #endif
 UNWIND(.fnend)
 ENDPROC(__gnu_mcount_nc)
-EXPORT_SYMBOL(__gnu_mcount_nc)
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 ENTRY(ftrace_caller)
index f41cee4c57467c5c6ab66d9f1d93d048f9b30171..04286fd9e09ce7a27259c4d375a05a965e3be0ea 100644 (file)
@@ -22,7 +22,6 @@
 #include <asm/memory.h>
 #include <asm/thread_info.h>
 #include <asm/pgtable.h>
-#include <asm/export.h>
 
 #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING)
 #include CONFIG_DEBUG_LL_INCLUDE
@@ -728,8 +727,6 @@ __pv_phys_pfn_offset:
 __pv_offset:
        .quad   0
        .size   __pv_offset, . -__pv_offset
-EXPORT_SYMBOL(__pv_phys_pfn_offset)
-EXPORT_SYMBOL(__pv_offset)
 #endif
 
 #include "head-common.S"
index 37669e7e13afd5483dc0acdfef22a77e9a090100..2e48b674aab190563d321902be9919167d8f80cd 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/opcodes-sec.h>
 #include <asm/opcodes-virt.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
        /*
         * Wrap c macros in asm macros to delay expansion until after the
@@ -52,7 +51,6 @@ UNWIND(       .fnend)
 ENTRY(arm_smccc_smc)
        SMCCC SMCCC_SMC
 ENDPROC(arm_smccc_smc)
-EXPORT_SYMBOL(arm_smccc_smc)
 
 /*
  * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
@@ -62,4 +60,3 @@ EXPORT_SYMBOL(arm_smccc_smc)
 ENTRY(arm_smccc_hvc)
        SMCCC SMCCC_HVC
 ENDPROC(arm_smccc_hvc)
-EXPORT_SYMBOL(arm_smccc_hvc)
index bc698383e82253a47427885359e07e22daa24179..9688ec0c6ef43f621d029c680fcd7876d120a53c 100644 (file)
@@ -74,6 +74,26 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long
                dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
 }
 
+void dump_backtrace_stm(u32 *stack, u32 instruction)
+{
+       char str[80], *p;
+       unsigned int x;
+       int reg;
+
+       for (reg = 10, x = 0, p = str; reg >= 0; reg--) {
+               if (instruction & BIT(reg)) {
+                       p += sprintf(p, " r%d:%08x", reg, *stack--);
+                       if (++x == 6) {
+                               x = 0;
+                               p = str;
+                               printk("%s\n", str);
+                       }
+               }
+       }
+       if (p != str)
+               printk("%s\n", str);
+}
+
 #ifndef CONFIG_ARM_UNWIND
 /*
  * Stack pointers should always be within the kernels view of
index 7fa487ef7e2f67fb3e1ac7fa8fd3edb58f2145fc..37b2a11af34592b5f60f0db77ce014588f9327f4 100644 (file)
@@ -3,6 +3,9 @@
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 
+/* No __ro_after_init data in the .rodata section - which will always be ro */
+#define RO_AFTER_INIT_DATA
+
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
@@ -223,6 +226,8 @@ SECTIONS
                . = ALIGN(PAGE_SIZE);
                __init_end = .;
 
+               *(.data..ro_after_init)
+
                NOSAVE_DATA
                CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
                READ_MOSTLY_DATA(L1_CACHE_BYTES)
index 03e9273f18765b039179dd87c0931d4d30b567c4..19b5f5c1c0ff3ef8fa68300f5ec87fe5564c916e 100644 (file)
@@ -114,11 +114,18 @@ void kvm_arch_check_processor_compat(void *rtn)
  */
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
-       int ret = 0;
+       int ret, cpu;
 
        if (type)
                return -EINVAL;
 
+       kvm->arch.last_vcpu_ran = alloc_percpu(typeof(*kvm->arch.last_vcpu_ran));
+       if (!kvm->arch.last_vcpu_ran)
+               return -ENOMEM;
+
+       for_each_possible_cpu(cpu)
+               *per_cpu_ptr(kvm->arch.last_vcpu_ran, cpu) = -1;
+
        ret = kvm_alloc_stage2_pgd(kvm);
        if (ret)
                goto out_fail_alloc;
@@ -141,6 +148,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 out_free_stage2_pgd:
        kvm_free_stage2_pgd(kvm);
 out_fail_alloc:
+       free_percpu(kvm->arch.last_vcpu_ran);
+       kvm->arch.last_vcpu_ran = NULL;
        return ret;
 }
 
@@ -168,6 +177,9 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 {
        int i;
 
+       free_percpu(kvm->arch.last_vcpu_ran);
+       kvm->arch.last_vcpu_ran = NULL;
+
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                if (kvm->vcpus[i]) {
                        kvm_arch_vcpu_free(kvm->vcpus[i]);
@@ -312,6 +324,19 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
+       int *last_ran;
+
+       last_ran = this_cpu_ptr(vcpu->kvm->arch.last_vcpu_ran);
+
+       /*
+        * We might get preempted before the vCPU actually runs, but
+        * over-invalidation doesn't affect correctness.
+        */
+       if (*last_ran != vcpu->vcpu_id) {
+               kvm_call_hyp(__kvm_tlb_flush_local_vmid, vcpu);
+               *last_ran = vcpu->vcpu_id;
+       }
+
        vcpu->cpu = cpu;
        vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
 
@@ -1312,6 +1337,13 @@ static int init_hyp_mode(void)
                goto out_err;
        }
 
+       err = create_hyp_mappings(kvm_ksym_ref(__bss_start),
+                                 kvm_ksym_ref(__bss_stop), PAGE_HYP_RO);
+       if (err) {
+               kvm_err("Cannot map bss section\n");
+               goto out_err;
+       }
+
        /*
         * Map the Hyp stack pages
         */
index 729652854f9098d677bd59871452c7b8c1ea240b..6d810af2d9fd7c630603ee5bfa8108c42a9992d8 100644 (file)
@@ -55,6 +55,21 @@ void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
        __kvm_tlb_flush_vmid(kvm);
 }
 
+void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
+{
+       struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
+
+       /* Switch to requested VMID */
+       write_sysreg(kvm->arch.vttbr, VTTBR);
+       isb();
+
+       write_sysreg(0, TLBIALL);
+       dsb(nsh);
+       isb();
+
+       write_sysreg(0, VTTBR);
+}
+
 void __hyp_text __kvm_flush_vm_context(void)
 {
        write_sysreg(0, TLBIALLNSNHIS);
index a7e7de89bd75c651e43c498384e97e39b98e5512..b05e95840651d0f5acc653a1efaeecd5c85b18fe 100644 (file)
@@ -28,7 +28,6 @@ Boston, MA 02110-1301, USA.  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 #ifdef __ARMEB__
 #define al r1
@@ -53,5 +52,3 @@ ENTRY(__aeabi_llsl)
 
 ENDPROC(__ashldi3)
 ENDPROC(__aeabi_llsl)
-EXPORT_SYMBOL(__ashldi3)
-EXPORT_SYMBOL(__aeabi_llsl)
index 490336e42518dddfc92b93cf4ef64c4105c377ec..275d7d2341a4e52e31e19924ebde00aaa771a49c 100644 (file)
@@ -28,7 +28,6 @@ Boston, MA 02110-1301, USA.  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 #ifdef __ARMEB__
 #define al r1
@@ -53,5 +52,3 @@ ENTRY(__aeabi_lasr)
 
 ENDPROC(__ashrdi3)
 ENDPROC(__aeabi_lasr)
-EXPORT_SYMBOL(__ashrdi3)
-EXPORT_SYMBOL(__aeabi_lasr)
index fab5a50503aedab7b4d875ff6acc1879ad3eeaa0..7d7952e5a3b1563e4245d91993ed11d664ddb3b3 100644 (file)
@@ -10,6 +10,7 @@
  * 27/03/03 Ian Molton Clean up CONFIG_CPU
  *
  */
+#include <linux/kern_levels.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
                .text
@@ -83,13 +84,13 @@ for_each_frame:     tst     frame, mask             @ Check for address exceptions
                teq     r3, r1, lsr #11
                ldreq   r0, [frame, #-8]        @ get sp
                subeq   r0, r0, #4              @ point at the last arg
-               bleq    .Ldumpstm               @ dump saved registers
+               bleq    dump_backtrace_stm      @ dump saved registers
 
 1004:          ldr     r1, [sv_pc, #0]         @ if stmfd sp!, {..., fp, ip, lr, pc}
                ldr     r3, .Ldsi               @ instruction exists,
                teq     r3, r1, lsr #11
                subeq   r0, frame, #16
-               bleq    .Ldumpstm               @ dump saved registers
+               bleq    dump_backtrace_stm      @ dump saved registers
 
                teq     sv_fp, #0               @ zero saved fp means
                beq     no_frame                @ no further frames
@@ -112,38 +113,6 @@ ENDPROC(c_backtrace)
                .long   1004b, 1006b
                .popsection
 
-#define instr r4
-#define reg   r5
-#define stack r6
-
-.Ldumpstm:     stmfd   sp!, {instr, reg, stack, r7, lr}
-               mov     stack, r0
-               mov     instr, r1
-               mov     reg, #10
-               mov     r7, #0
-1:             mov     r3, #1
- ARM(          tst     instr, r3, lsl reg      )
- THUMB(                lsl     r3, reg                 )
- THUMB(                tst     instr, r3               )
-               beq     2f
-               add     r7, r7, #1
-               teq     r7, #6
-               moveq   r7, #0
-               adr     r3, .Lcr
-               addne   r3, r3, #1              @ skip newline
-               ldr     r2, [stack], #-4
-               mov     r1, reg
-               adr     r0, .Lfp
-               bl      printk
-2:             subs    reg, reg, #1
-               bpl     1b
-               teq     r7, #0
-               adrne   r0, .Lcr
-               blne    printk
-               ldmfd   sp!, {instr, reg, stack, r7, pc}
-
-.Lfp:          .asciz  " r%d:%08x%s"
-.Lcr:          .asciz  "\n"
 .Lbad:         .asciz  "Backtrace aborted due to bad frame pointer <%p>\n"
                .align
 .Ldsi:         .word   0xe92dd800 >> 11        @ stmfd sp!, {... fp, ip, lr, pc}
index df06638b327cda70a5421b851467bb88c6d3fa08..7d807cfd8ef57ed2bdde29d98ddb6a7094f725f7 100644 (file)
@@ -1,6 +1,5 @@
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
 #if __LINUX_ARM_ARCH__ >= 6
        .macro  bitop, name, instr
@@ -26,7 +25,6 @@ UNWIND(       .fnstart        )
        bx      lr
 UNWIND(        .fnend          )
 ENDPROC(\name          )
-EXPORT_SYMBOL(\name    )
        .endm
 
        .macro  testop, name, instr, store
@@ -57,7 +55,6 @@ UNWIND(       .fnstart        )
 2:     bx      lr
 UNWIND(        .fnend          )
 ENDPROC(\name          )
-EXPORT_SYMBOL(\name    )
        .endm
 #else
        .macro  bitop, name, instr
@@ -77,7 +74,6 @@ UNWIND(       .fnstart        )
        ret     lr
 UNWIND(        .fnend          )
 ENDPROC(\name          )
-EXPORT_SYMBOL(\name    )
        .endm
 
 /**
@@ -106,6 +102,5 @@ UNWIND(     .fnstart        )
        ret     lr
 UNWIND(        .fnend          )
 ENDPROC(\name          )
-EXPORT_SYMBOL(\name    )
        .endm
 #endif
index f05f78247304bb41d18dda92c6c674e86a84c90b..07cda737bb11f14ed1c873e7e2c5b97c2da2543e 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 #if __LINUX_ARM_ARCH__ >= 6
 ENTRY(__bswapsi2)
@@ -36,5 +35,3 @@ ENTRY(__bswapdi2)
        ret lr
 ENDPROC(__bswapdi2)
 #endif
-EXPORT_SYMBOL(__bswapsi2)
-EXPORT_SYMBOL(__bswapdi2)
index b566154f5cf4ede9b1e487570519d2b01309f771..e936352ccb0013e040fcd9b22bda1c583cfff361 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
                .text
 
@@ -51,9 +50,6 @@ USER(         strnebt r2, [r0])
 UNWIND(.fnend)
 ENDPROC(arm_clear_user)
 ENDPROC(__clear_user_std)
-#ifndef CONFIG_UACCESS_WITH_MEMCPY
-EXPORT_SYMBOL(arm_clear_user)
-#endif
 
                .pushsection .text.fixup,"ax"
                .align  0
index 63e4c1ed0225c8770fc9e29f311809bacdd2d95f..7a4b060490012dd29f8a6d9fb8e24dfa58896bd1 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
 /*
  * Prototype:
@@ -95,7 +94,6 @@ ENTRY(arm_copy_from_user)
 #include "copy_template.S"
 
 ENDPROC(arm_copy_from_user)
-EXPORT_SYMBOL(arm_copy_from_user)
 
        .pushsection .fixup,"ax"
        .align 0
index d97851d4af7a43f818240a687babff17ded0f06f..6ee2f6706f869b03c95f30d2b1a1cf7adf9086d9 100644 (file)
@@ -13,7 +13,6 @@
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
-#include <asm/export.h>
 
 #define COPY_COUNT (PAGE_SZ / (2 * L1_CACHE_BYTES) PLD( -1 ))
 
@@ -46,4 +45,3 @@ ENTRY(copy_page)
        PLD(    beq     2b                      )
                ldmfd   sp!, {r4, pc}                   @       3
 ENDPROC(copy_page)
-EXPORT_SYMBOL(copy_page)
index 592c179112d1b5a2810c869774a2721be95e2a4d..caf5019d8161e2f1914a797a4c6800844a27d570 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
 /*
  * Prototype:
@@ -100,9 +99,6 @@ WEAK(arm_copy_to_user)
 
 ENDPROC(arm_copy_to_user)
 ENDPROC(__copy_to_user_std)
-#ifndef CONFIG_UACCESS_WITH_MEMCPY
-EXPORT_SYMBOL(arm_copy_to_user)
-#endif
 
        .pushsection .text.fixup,"ax"
        .align 0
index 68603b5ee53723d9e75f15922d0c193c2579e4e2..3ac6ef01bc43a4cc13465822ead08f18eb88ea0c 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
                .text
 
@@ -31,4 +30,4 @@ ENTRY(__csum_ipv6_magic)
                adcs    r0, r0, #0
                ldmfd   sp!, {pc}
 ENDPROC(__csum_ipv6_magic)
-EXPORT_SYMBOL(__csum_ipv6_magic)
+
index 830b20e81c3783a7f27c209d401b3281eb5846d1..984e0f29d548b456884e643d9f9337e4cd42fc31 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
                .text
 
@@ -141,4 +140,3 @@ ENTRY(csum_partial)
                bne     4b
                b       .Lless4
 ENDPROC(csum_partial)
-EXPORT_SYMBOL(csum_partial)
index 9c3383fed129b9b9de1edb573ef4b23ac2505c1d..d03fc71fc88c9d5167290ee0d2228f5efca820ec 100644 (file)
@@ -49,6 +49,5 @@
 
 #define FN_ENTRY       ENTRY(csum_partial_copy_nocheck)
 #define FN_EXIT                ENDPROC(csum_partial_copy_nocheck)
-#define FN_EXPORT      EXPORT_SYMBOL(csum_partial_copy_nocheck)
 
 #include "csumpartialcopygeneric.S"
index 8b94d20e51d1757706773cd6bc7fad513a16fc05..10b45909610ca6f4ca6f6f8bdc664b79c2f2bd6f 100644 (file)
@@ -8,7 +8,6 @@
  * published by the Free Software Foundation.
  */
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 /*
  * unsigned int
@@ -332,4 +331,3 @@ FN_ENTRY
                mov     r5, r4, get_byte_1
                b       .Lexit
 FN_EXIT
-FN_EXPORT
index 5d495edf3d83f5e166b98f2344f5553e2b1866d8..1712f132b80d2402d94d72ea974a0c3326fa2f52 100644 (file)
@@ -73,7 +73,6 @@
 
 #define FN_ENTRY       ENTRY(csum_partial_copy_from_user)
 #define FN_EXIT                ENDPROC(csum_partial_copy_from_user)
-#define FN_EXPORT      EXPORT_SYMBOL(csum_partial_copy_from_user)
 
 #include "csumpartialcopygeneric.S"
 
index 69aad80a3af4bd7bfe8f4369bd0e09ac413ff39f..2cef11884857dd952f1f3e99bb259470fd3e3d78 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/export.h>
 #include <linux/timex.h>
 
 /*
@@ -35,7 +34,6 @@ struct arm_delay_ops arm_delay_ops __ro_after_init = {
        .const_udelay   = __loop_const_udelay,
        .udelay         = __loop_udelay,
 };
-EXPORT_SYMBOL(arm_delay_ops);
 
 static const struct delay_timer *delay_timer;
 static bool delay_calibrated;
index 0c9e1c18fc9eca384d4d98c3eacb2993a1f0f94f..a9eafe4981eb847e2f07e0e245aa8e1f1747fa59 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
 #ifdef __ARMEB__
 #define xh r0
@@ -211,4 +210,3 @@ Ldiv0_64:
 
 UNWIND(.fnend)
 ENDPROC(__do_div64)
-EXPORT_SYMBOL(__do_div64)
index 26302b8cd38fba8c61d40e3bedc901637efc9f19..7848780e883473ac21d97ed54b99ec3788672980 100644 (file)
@@ -15,7 +15,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
                 .text
 
 /*
@@ -38,7 +37,6 @@ ENTRY(_find_first_zero_bit_le)
 3:             mov     r0, r1                  @ no free bits
                ret     lr
 ENDPROC(_find_first_zero_bit_le)
-EXPORT_SYMBOL(_find_first_zero_bit_le)
 
 /*
  * Purpose  : Find next 'zero' bit
@@ -59,7 +57,6 @@ ENTRY(_find_next_zero_bit_le)
                add     r2, r2, #1              @ align bit pointer
                b       2b                      @ loop for next bit
 ENDPROC(_find_next_zero_bit_le)
-EXPORT_SYMBOL(_find_next_zero_bit_le)
 
 /*
  * Purpose  : Find a 'one' bit
@@ -81,7 +78,6 @@ ENTRY(_find_first_bit_le)
 3:             mov     r0, r1                  @ no free bits
                ret     lr
 ENDPROC(_find_first_bit_le)
-EXPORT_SYMBOL(_find_first_bit_le)
 
 /*
  * Purpose  : Find next 'one' bit
@@ -101,7 +97,6 @@ ENTRY(_find_next_bit_le)
                add     r2, r2, #1              @ align bit pointer
                b       2b                      @ loop for next bit
 ENDPROC(_find_next_bit_le)
-EXPORT_SYMBOL(_find_next_bit_le)
 
 #ifdef __ARMEB__
 
@@ -121,7 +116,6 @@ ENTRY(_find_first_zero_bit_be)
 3:             mov     r0, r1                  @ no free bits
                ret     lr
 ENDPROC(_find_first_zero_bit_be)
-EXPORT_SYMBOL(_find_first_zero_bit_be)
 
 ENTRY(_find_next_zero_bit_be)
                teq     r1, #0
@@ -139,7 +133,6 @@ ENTRY(_find_next_zero_bit_be)
                add     r2, r2, #1              @ align bit pointer
                b       2b                      @ loop for next bit
 ENDPROC(_find_next_zero_bit_be)
-EXPORT_SYMBOL(_find_next_zero_bit_be)
 
 ENTRY(_find_first_bit_be)
                teq     r1, #0
@@ -157,7 +150,6 @@ ENTRY(_find_first_bit_be)
 3:             mov     r0, r1                  @ no free bits
                ret     lr
 ENDPROC(_find_first_bit_be)
-EXPORT_SYMBOL(_find_first_bit_be)
 
 ENTRY(_find_next_bit_be)
                teq     r1, #0
@@ -174,7 +166,6 @@ ENTRY(_find_next_bit_be)
                add     r2, r2, #1              @ align bit pointer
                b       2b                      @ loop for next bit
 ENDPROC(_find_next_bit_be)
-EXPORT_SYMBOL(_find_next_bit_be)
 
 #endif
 
index 9d09a38e73af361e6939e53cb0303e14322a750e..8ecfd15c3a0248db29667fe3dc6ec6429fc9fc7c 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/assembler.h>
 #include <asm/errno.h>
 #include <asm/domain.h>
-#include <asm/export.h>
 
 ENTRY(__get_user_1)
        check_uaccess r0, 1, r1, r2, __get_user_bad
@@ -39,7 +38,6 @@ ENTRY(__get_user_1)
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_1)
-EXPORT_SYMBOL(__get_user_1)
 
 ENTRY(__get_user_2)
        check_uaccess r0, 2, r1, r2, __get_user_bad
@@ -60,7 +58,6 @@ rb    .req    r0
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_2)
-EXPORT_SYMBOL(__get_user_2)
 
 ENTRY(__get_user_4)
        check_uaccess r0, 4, r1, r2, __get_user_bad
@@ -68,7 +65,6 @@ ENTRY(__get_user_4)
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_4)
-EXPORT_SYMBOL(__get_user_4)
 
 ENTRY(__get_user_8)
        check_uaccess r0, 8, r1, r2, __get_user_bad
@@ -82,7 +78,6 @@ ENTRY(__get_user_8)
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_8)
-EXPORT_SYMBOL(__get_user_8)
 
 #ifdef __ARMEB__
 ENTRY(__get_user_32t_8)
@@ -96,7 +91,6 @@ ENTRY(__get_user_32t_8)
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_32t_8)
-EXPORT_SYMBOL(__get_user_32t_8)
 
 ENTRY(__get_user_64t_1)
        check_uaccess r0, 1, r1, r2, __get_user_bad8
@@ -104,7 +98,6 @@ ENTRY(__get_user_64t_1)
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_64t_1)
-EXPORT_SYMBOL(__get_user_64t_1)
 
 ENTRY(__get_user_64t_2)
        check_uaccess r0, 2, r1, r2, __get_user_bad8
@@ -121,7 +114,6 @@ rb  .req    r0
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_64t_2)
-EXPORT_SYMBOL(__get_user_64t_2)
 
 ENTRY(__get_user_64t_4)
        check_uaccess r0, 4, r1, r2, __get_user_bad8
@@ -129,7 +121,6 @@ ENTRY(__get_user_64t_4)
        mov     r0, #0
        ret     lr
 ENDPROC(__get_user_64t_4)
-EXPORT_SYMBOL(__get_user_64t_4)
 #endif
 
 __get_user_bad8:
index 3dff7a3a2aef057ffb55525ded4cf10d45137f0c..c31b2f3153f171fd09602aed2ea9cb8c97797f4d 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 .Linsb_align:  rsb     ip, ip, #4
                cmp     ip, r2
@@ -122,4 +121,3 @@ ENTRY(__raw_readsb)
 
                ldmfd   sp!, {r4 - r6, pc}
 ENDPROC(__raw_readsb)
-EXPORT_SYMBOL(__raw_readsb)
index bfd39682325b0c43ba990a130cc14afca9d87104..2ed86fa5465f70cdcb92a46a167d9aa81edad68f 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 ENTRY(__raw_readsl)
                teq     r2, #0          @ do we have to check for the zero len?
@@ -78,4 +77,3 @@ ENTRY(__raw_readsl)
                strb    r3, [r1, #0]
                ret     lr
 ENDPROC(__raw_readsl)
-EXPORT_SYMBOL(__raw_readsl)
index b3af3db6caac8bd7e2a41f21c0098dbb00b5568f..413da99145292f3e535b618fee2a5c9c96e114b4 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 .Linsw_bad_alignment:
                adr     r0, .Linsw_bad_align_msg
@@ -104,4 +103,4 @@ ENTRY(__raw_readsw)
 
                ldmfd   sp!, {r4, r5, r6, pc}
 
-EXPORT_SYMBOL(__raw_readsw)
+
index 3c7a7a40b33ead61b3e1255674243e7894c92963..d9a45e9692aee3ad1de5dea37653a65cd8c18da4 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
                .macro  pack, rd, hw1, hw2
 #ifndef __ARMEB__
@@ -130,4 +129,3 @@ ENTRY(__raw_readsw)
                strneb  ip, [r1]
                ldmfd   sp!, {r4, pc}
 ENDPROC(__raw_readsw)
-EXPORT_SYMBOL(__raw_readsw)
index fa36335944159050eceedba7fcb1505c42e79f15..a46bbc9b168b45f7016096244eb4933a911d4ac0 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
                .macro  outword, rd
 #ifndef __ARMEB__
@@ -93,4 +92,3 @@ ENTRY(__raw_writesb)
 
                ldmfd   sp!, {r4, r5, pc}
 ENDPROC(__raw_writesb)
-EXPORT_SYMBOL(__raw_writesb)
index 98ed6aec0b4767df744bb9ca8581a29bb507c1a3..4ea2435988c1f75d8fddac8ac63a499067d02cae 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 ENTRY(__raw_writesl)
                teq     r2, #0          @ do we have to check for the zero len?
@@ -66,4 +65,3 @@ ENTRY(__raw_writesl)
                bne     6b
                ret     lr
 ENDPROC(__raw_writesl)
-EXPORT_SYMBOL(__raw_writesl)
index 577184c082bb6192f5734baef70d0667dcced5c2..121789eb680235f9dad2c8f1492960d2f26fded1 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 .Loutsw_bad_alignment:
                adr     r0, .Loutsw_bad_align_msg
@@ -125,4 +124,3 @@ ENTRY(__raw_writesw)
                strne   ip, [r0]
 
                ldmfd   sp!, {r4, r5, r6, pc}
-EXPORT_SYMBOL(__raw_writesw)
index e335f489d1fcda8201728dd061c4802d4cbf7a58..269f90c51ad279c63bf4dd9f8bfed8c6827a75d2 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
                .macro  outword, rd
 #ifndef __ARMEB__
@@ -99,4 +98,3 @@ ENTRY(__raw_writesw)
                strneh  ip, [r0]
                ret     lr
 ENDPROC(__raw_writesw)
-EXPORT_SYMBOL(__raw_writesw)
index f541bc013bff63398f7462da233de6bf2cd96ee6..9397b2e532afa3d863930b4e29a663c166ae475e 100644 (file)
@@ -36,7 +36,6 @@ Boston, MA 02111-1307, USA.  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
 .macro ARM_DIV_BODY dividend, divisor, result, curbit
 
@@ -239,8 +238,6 @@ UNWIND(.fnstart)
 UNWIND(.fnend)
 ENDPROC(__udivsi3)
 ENDPROC(__aeabi_uidiv)
-EXPORT_SYMBOL(__udivsi3)
-EXPORT_SYMBOL(__aeabi_uidiv)
 
 ENTRY(__umodsi3)
 UNWIND(.fnstart)
@@ -259,7 +256,6 @@ UNWIND(.fnstart)
 
 UNWIND(.fnend)
 ENDPROC(__umodsi3)
-EXPORT_SYMBOL(__umodsi3)
 
 #ifdef CONFIG_ARM_PATCH_IDIV
        .align 3
@@ -307,8 +303,6 @@ UNWIND(.fnstart)
 UNWIND(.fnend)
 ENDPROC(__divsi3)
 ENDPROC(__aeabi_idiv)
-EXPORT_SYMBOL(__divsi3)
-EXPORT_SYMBOL(__aeabi_idiv)
 
 ENTRY(__modsi3)
 UNWIND(.fnstart)
@@ -333,7 +327,6 @@ UNWIND(.fnstart)
 
 UNWIND(.fnend)
 ENDPROC(__modsi3)
-EXPORT_SYMBOL(__modsi3)
 
 #ifdef CONFIG_AEABI
 
@@ -350,7 +343,6 @@ UNWIND(.save {r0, r1, ip, lr}       )
 
 UNWIND(.fnend)
 ENDPROC(__aeabi_uidivmod)
-EXPORT_SYMBOL(__aeabi_uidivmod)
 
 ENTRY(__aeabi_idivmod)
 UNWIND(.fnstart)
@@ -364,7 +356,6 @@ UNWIND(.save {r0, r1, ip, lr}       )
 
 UNWIND(.fnend)
 ENDPROC(__aeabi_idivmod)
-EXPORT_SYMBOL(__aeabi_idivmod)
 
 #endif
 
index e408339814174a0b6d826699789c7f1f96778814..922dcd88b02b7804fca63f0d891e9a7ed6cbf83e 100644 (file)
@@ -28,7 +28,6 @@ Boston, MA 02110-1301, USA.  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 #ifdef __ARMEB__
 #define al r1
@@ -53,5 +52,3 @@ ENTRY(__aeabi_llsr)
 
 ENDPROC(__lshrdi3)
 ENDPROC(__aeabi_llsr)
-EXPORT_SYMBOL(__lshrdi3)
-EXPORT_SYMBOL(__aeabi_llsr)
index 44182bf686a51cb17e483035482208a8889a28a3..74a5bed6d9999a645d06d6d34369f9b7c155c0f9 100644 (file)
@@ -11,7 +11,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
        .text
        .align  5
@@ -25,4 +24,3 @@ ENTRY(memchr)
 2:     movne   r0, #0
        ret     lr
 ENDPROC(memchr)
-EXPORT_SYMBOL(memchr)
index 1be5b6ddf37c820910ad260a2a243515d07549c4..64111bd4440b1aa3702c469ce349b303a0244ebd 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
 #define LDR1W_SHIFT    0
 #define STR1W_SHIFT    0
@@ -69,5 +68,3 @@ ENTRY(memcpy)
 
 ENDPROC(memcpy)
 ENDPROC(mmiocpy)
-EXPORT_SYMBOL(memcpy)
-EXPORT_SYMBOL(mmiocpy)
index 71dcc5400d025670ca7bdb872f24c83f88650e81..69a9d47fc5abdcb9f1801cbfe249eaed99b00d99 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
                .text
 
@@ -226,4 +225,3 @@ ENTRY(memmove)
 18:            backward_copy_shift     push=24 pull=8
 
 ENDPROC(memmove)
-EXPORT_SYMBOL(memmove)
index 7b72044cba62f9c45d693999ebf3e6bb5bdff18a..3c65e3bd790fe1f7aec59d9568cb4c0799be0e9a 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
        .text
        .align  5
@@ -136,5 +135,3 @@ UNWIND( .fnstart            )
 UNWIND( .fnend   )
 ENDPROC(memset)
 ENDPROC(mmioset)
-EXPORT_SYMBOL(memset)
-EXPORT_SYMBOL(mmioset)
index 6dec26ed5bccde9c6e5ba3819022e9e0cf95ea56..0eded952e0896eddcfdb95acc3fd42cefee4aef3 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/unwind.h>
-#include <asm/export.h>
 
        .text
        .align  5
@@ -136,4 +135,3 @@ UNWIND(     .fnstart                        )
        ret     lr                      @ 1
 UNWIND(        .fnend                          )
 ENDPROC(__memzero)
-EXPORT_SYMBOL(__memzero)
index b8f12388ccaca25e4babea56e7645dfde0de425d..20430595692500b7442a39f6b483b2af9afd0b2c 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 #ifdef __ARMEB__
 #define xh r0
@@ -47,5 +46,3 @@ ENTRY(__aeabi_lmul)
 
 ENDPROC(__muldi3)
 ENDPROC(__aeabi_lmul)
-EXPORT_SYMBOL(__muldi3)
-EXPORT_SYMBOL(__aeabi_lmul)
index 11de126e2ed6bc757f5185ccf8ef0fe5551c6c08..38d660d3705f4f259c5299d2cc8c1126f0a1dbb4 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/assembler.h>
 #include <asm/errno.h>
 #include <asm/domain.h>
-#include <asm/export.h>
 
 ENTRY(__put_user_1)
        check_uaccess r0, 1, r1, ip, __put_user_bad
@@ -39,7 +38,6 @@ ENTRY(__put_user_1)
        mov     r0, #0
        ret     lr
 ENDPROC(__put_user_1)
-EXPORT_SYMBOL(__put_user_1)
 
 ENTRY(__put_user_2)
        check_uaccess r0, 2, r1, ip, __put_user_bad
@@ -64,7 +62,6 @@ ENTRY(__put_user_2)
        mov     r0, #0
        ret     lr
 ENDPROC(__put_user_2)
-EXPORT_SYMBOL(__put_user_2)
 
 ENTRY(__put_user_4)
        check_uaccess r0, 4, r1, ip, __put_user_bad
@@ -72,7 +69,6 @@ ENTRY(__put_user_4)
        mov     r0, #0
        ret     lr
 ENDPROC(__put_user_4)
-EXPORT_SYMBOL(__put_user_4)
 
 ENTRY(__put_user_8)
        check_uaccess r0, 8, r1, ip, __put_user_bad
@@ -86,7 +82,6 @@ ENTRY(__put_user_8)
        mov     r0, #0
        ret     lr
 ENDPROC(__put_user_8)
-EXPORT_SYMBOL(__put_user_8)
 
 __put_user_bad:
        mov     r0, #-EFAULT
index 7301f6e6046c1bb33ba6e6f206418dddbdfc312b..013d64c71e8d6aae7b0d9f826b13dbca1e32f22d 100644 (file)
@@ -11,7 +11,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
                .text
                .align  5
@@ -26,4 +25,3 @@ ENTRY(strchr)
                subeq   r0, r0, #1
                ret     lr
 ENDPROC(strchr)
-EXPORT_SYMBOL(strchr)
index aaf9fd98b7548d0c045cfefa5e35cf5bfefb8349..3cec1c7482c49dbae6450af7bc66f72dfb7179c6 100644 (file)
@@ -11,7 +11,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
                .text
                .align  5
@@ -25,4 +24,3 @@ ENTRY(strrchr)
                mov     r0, r3
                ret     lr
 ENDPROC(strrchr)
-EXPORT_SYMBOL(strrchr)
index 1626e3a551a14e53e08659311122c7fc51ae557f..6bd1089b07e0960830ed6bd6a8345202b7efd8b0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/hugetlb.h>
-#include <linux/export.h>
 #include <asm/current.h>
 #include <asm/page.h>
 
@@ -157,7 +156,6 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
        }
        return n;
 }
-EXPORT_SYMBOL(arm_copy_to_user);
        
 static unsigned long noinline
 __clear_user_memset(void __user *addr, unsigned long n)
@@ -215,7 +213,6 @@ unsigned long arm_clear_user(void __user *addr, unsigned long n)
        }
        return n;
 }
-EXPORT_SYMBOL(arm_clear_user);
 
 #if 0
 
index 127a91af46f3adc2c502d674518dac7645b2bf7a..ad4a6309141a59c0ba3534795b93c5dbe7876814 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 #ifdef __ARMEB__
 #define xh r0
@@ -36,7 +35,6 @@ ENTRY(__ucmpdi2)
        ret     lr
 
 ENDPROC(__ucmpdi2)
-EXPORT_SYMBOL(__ucmpdi2)
 
 #ifdef CONFIG_AEABI
 
@@ -50,7 +48,6 @@ ENTRY(__aeabi_ulcmp)
        ret     lr
 
 ENDPROC(__aeabi_ulcmp)
-EXPORT_SYMBOL(__aeabi_ulcmp)
 
 #endif
 
index 737450fe790c37fdb42ec122aa5147ccbadd3cc0..cab128913e72a710a0f405336b0d814e56935546 100644 (file)
@@ -32,6 +32,7 @@ endif
 
 ifdef CONFIG_SND_IMX_SOC
 obj-y += ssi-fiq.o
+obj-y += ssi-fiq-ksym.o
 endif
 
 # i.MX21 based machines
index 0df062d8b2c942f84a31a923e0a4f221c6c9366d..b54db47f6f322d358f7742ecc7e17b23e0c2b667 100644 (file)
@@ -408,7 +408,7 @@ static struct genpd_onecell_data imx_gpc_onecell_data = {
 static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
 {
        struct clk *clk;
-       int i;
+       int i, ret;
 
        imx6q_pu_domain.reg = pu_reg;
 
@@ -430,13 +430,22 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
        if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
                return 0;
 
-       pm_genpd_init(&imx6q_pu_domain.base, NULL, false);
-       return of_genpd_add_provider_onecell(dev->of_node,
+       for (i = 0; i < ARRAY_SIZE(imx_gpc_domains); i++)
+               pm_genpd_init(imx_gpc_domains[i], NULL, false);
+
+       ret =  of_genpd_add_provider_onecell(dev->of_node,
                                             &imx_gpc_onecell_data);
+       if (ret)
+               goto power_off;
+
+       return 0;
 
+power_off:
+       imx6q_pm_pu_power_off(&imx6q_pu_domain.base);
 clk_err:
        while (i--)
                clk_put(imx6q_pu_domain.clk[i]);
+       imx6q_pu_domain.reg = NULL;
        return -EINVAL;
 }
 
index 97fd25105e2c0d1e0e1bb5a0a14471e4be0842f6..45801b27ee5ced633fae6a7c6ca238cf203f0056 100644 (file)
@@ -173,7 +173,7 @@ static void __init imx6q_enet_phy_init(void)
                                ksz9021rn_phy_fixup);
                phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,
                                ksz9031rn_phy_fixup);
-               phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
+               phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffef,
                                ar8031_phy_fixup);
                phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef,
                                ar8035_phy_fixup);
diff --git a/arch/arm/mach-imx/ssi-fiq-ksym.c b/arch/arm/mach-imx/ssi-fiq-ksym.c
new file mode 100644 (file)
index 0000000..792090f
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Exported ksyms for the SSI FIQ handler
+ *
+ * Copyright (C) 2009, Sascha Hauer <s.hauer@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 Free Software Foundation.
+ */
+
+#include <linux/module.h>
+
+#include <linux/platform_data/asoc-imx-ssi.h>
+
+EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer);
+EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer);
+EXPORT_SYMBOL(imx_ssi_fiq_start);
+EXPORT_SYMBOL(imx_ssi_fiq_end);
+EXPORT_SYMBOL(imx_ssi_fiq_base);
+
index fd7917f1c20410d5df584c22bc043eddb0984987..a8b93c5f29b5321a3b0ef341cfb07d601218a2d2 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <asm/export.h>
 
 /*
  * r8  = bit 0-15: tx offset, bit 16-31: tx buffer size
@@ -145,8 +144,4 @@ imx_ssi_fiq_tx_buffer:
                .word 0x0
 .L_imx_ssi_fiq_end:
 imx_ssi_fiq_end:
-EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer)
-EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer)
-EXPORT_SYMBOL(imx_ssi_fiq_start)
-EXPORT_SYMBOL(imx_ssi_fiq_end)
-EXPORT_SYMBOL(imx_ssi_fiq_base)
+
index f9b6bd306cfea8fc29d48485e47b60c701b21df3..541647f5719255cfd755a22b0435f97426e92612 100644 (file)
@@ -23,6 +23,7 @@ config MACH_MVEBU_V7
        select CACHE_L2X0
        select ARM_CPU_SUSPEND
        select MACH_MVEBU_ANY
+       select MVEBU_CLK_COREDIV
 
 config MACH_ARMADA_370
        bool "Marvell Armada 370 boards"
@@ -32,7 +33,6 @@ config MACH_ARMADA_370
        select CPU_PJ4B
        select MACH_MVEBU_V7
        select PINCTRL_ARMADA_370
-       select MVEBU_CLK_COREDIV
        help
          Say 'Y' here if you want your kernel to support boards based
          on the Marvell Armada 370 SoC with device tree.
@@ -50,7 +50,6 @@ config MACH_ARMADA_375
        select HAVE_SMP
        select MACH_MVEBU_V7
        select PINCTRL_ARMADA_375
-       select MVEBU_CLK_COREDIV
        help
          Say 'Y' here if you want your kernel to support boards based
          on the Marvell Armada 375 SoC with device tree.
@@ -68,7 +67,6 @@ config MACH_ARMADA_38X
        select HAVE_SMP
        select MACH_MVEBU_V7
        select PINCTRL_ARMADA_38X
-       select MVEBU_CLK_COREDIV
        help
          Say 'Y' here if you want your kernel to support boards based
          on the Marvell Armada 380/385 SoC with device tree.
index a9afeebd59f222c0db294858d50f2c2f8a3889e2..0465338183c706721d94d356683fad3fa17a4435 100644 (file)
@@ -71,6 +71,7 @@ config SOC_AM43XX
        select HAVE_ARM_TWD
        select ARM_ERRATA_754322
        select ARM_ERRATA_775420
+       select OMAP_INTERCONNECT
 
 config SOC_DRA7XX
        bool "TI DRA7XX"
index 2abd53ae3e7a13f5801b7680ebd65464f2bede5c..cc6d9fa609242e2cb4660db80de5092b95ddd636 100644 (file)
@@ -205,11 +205,15 @@ void __init omap2xxx_check_revision(void)
 
 #define OMAP3_SHOW_FEATURE(feat)               \
        if (omap3_has_ ##feat())                \
-               printk(#feat" ");
+               n += scnprintf(buf + n, sizeof(buf) - n, #feat " ");
 
 static void __init omap3_cpuinfo(void)
 {
        const char *cpu_name;
+       char buf[64];
+       int n = 0;
+
+       memset(buf, 0, sizeof(buf));
 
        /*
         * OMAP3430 and OMAP3530 are assumed to be same.
@@ -241,10 +245,10 @@ static void __init omap3_cpuinfo(void)
                cpu_name = "OMAP3503";
        }
 
-       sprintf(soc_name, "%s", cpu_name);
+       scnprintf(soc_name, sizeof(soc_name), "%s", cpu_name);
 
        /* Print verbose information */
-       pr_info("%s %s (", soc_name, soc_rev);
+       n += scnprintf(buf, sizeof(buf) - n, "%s %s (", soc_name, soc_rev);
 
        OMAP3_SHOW_FEATURE(l2cache);
        OMAP3_SHOW_FEATURE(iva);
@@ -252,8 +256,10 @@ static void __init omap3_cpuinfo(void)
        OMAP3_SHOW_FEATURE(neon);
        OMAP3_SHOW_FEATURE(isp);
        OMAP3_SHOW_FEATURE(192mhz_clk);
-
-       printk(")\n");
+       if (*(buf + n - 1) == ' ')
+               n--;
+       n += scnprintf(buf + n, sizeof(buf) - n, ")\n");
+       pr_info("%s", buf);
 }
 
 #define OMAP3_CHECK_FEATURE(status,feat)                               \
index 62680aad212666af7f07131546ff1e9bc01c2572..718981bb80cdf594d77c6b0d5d5067c806729862 100644 (file)
@@ -319,6 +319,9 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva)
        if (has_uart4) {
                en_uart4_mask = OMAP3630_EN_UART4_MASK;
                grpsel_uart4_mask = OMAP3630_GRPSEL_UART4_MASK;
+       } else {
+               en_uart4_mask = 0;
+               grpsel_uart4_mask = 0;
        }
 
        /* Enable wakeups in PER */
index cba8cada8c81a07a9cd5ee7ebc12108aa41597a5..cd15dbd62671690388b841199d2c18f52811504f 100644 (file)
@@ -87,6 +87,12 @@ int voltdm_scale(struct voltagedomain *voltdm,
                return -ENODATA;
        }
 
+       if (!voltdm->volt_data) {
+               pr_err("%s: No voltage data defined for vdd_%s\n",
+                       __func__, voltdm->name);
+               return -ENODATA;
+       }
+
        /* Adjust voltage to the exact voltage from the OPP table */
        for (i = 0; voltdm->volt_data[i].volt_nominal != 0; i++) {
                if (voltdm->volt_data[i].volt_nominal >= target_volt) {
index 82dddee3a469be64a585b0d3c69003aec87ff543..3930fbba30b4b3ccedd2039c552c5956cdd8d84a 100644 (file)
@@ -1,6 +1,7 @@
 config ARCH_UNIPHIER
        bool "Socionext UniPhier SoCs"
        depends on ARCH_MULTI_V7
+       select ARCH_HAS_RESET_CONTROLLER
        select ARM_AMBA
        select ARM_GLOBAL_TIMER
        select ARM_GIC
index 6d8e8e3365d17321f03b37fa67ab04a65b29f4ca..4cdfab31a0b612d11f1ad88c7985e007620fdca1 100644 (file)
@@ -7,7 +7,7 @@
  *        : r4 = aborted context pc
  *        : r5 = aborted context psr
  *
- * Returns : r4-r5, r10-r11, r13 preserved
+ * Returns : r4-r5, r9-r11, r13 preserved
  *
  * Purpose : obtain information about current aborted instruction.
  * Note: we read user space.  This means we might cause a data
@@ -48,7 +48,10 @@ ENTRY(v4t_late_abort)
 /* c */        b       do_DataAbort                    @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
 /* d */        b       do_DataAbort                    @ ldc   rd, [rn, #m]
 /* e */        b       .data_unknown
-/* f */
+/* f */        b       .data_unknown
+
+.data_unknown_r9:
+       ldr     r9, [sp], #4
 .data_unknown: @ Part of jumptable
        mov     r0, r4
        mov     r1, r8
@@ -57,6 +60,7 @@ ENTRY(v4t_late_abort)
 .data_arm_ldmstm:
        tst     r8, #1 << 21                    @ check writeback bit
        beq     do_DataAbort                    @ no writeback -> no fixup
+       str     r9, [sp, #-4]!
        mov     r7, #0x11
        orr     r7, r7, #0x1100
        and     r6, r8, r7
@@ -75,12 +79,14 @@ ENTRY(v4t_late_abort)
        subne   r7, r7, r6, lsl #2              @ Undo increment
        addeq   r7, r7, r6, lsl #2              @ Undo decrement
        str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
+       ldr     r9, [sp], #4
        b       do_DataAbort
 
 .data_arm_lateldrhpre:
        tst     r8, #1 << 21                    @ Check writeback bit
        beq     do_DataAbort                    @ No writeback -> no fixup
 .data_arm_lateldrhpost:
+       str     r9, [sp, #-4]!
        and     r9, r8, #0x00f                  @ get Rm / low nibble of immediate value
        tst     r8, #1 << 22                    @ if (immediate offset)
        andne   r6, r8, #0xf00                  @ { immediate high nibble
@@ -93,6 +99,7 @@ ENTRY(v4t_late_abort)
        subne   r7, r7, r6                      @ Undo incrmenet
        addeq   r7, r7, r6                      @ Undo decrement
        str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
+       ldr     r9, [sp], #4
        b       do_DataAbort
 
 .data_arm_lateldrpreconst:
@@ -101,12 +108,14 @@ ENTRY(v4t_late_abort)
 .data_arm_lateldrpostconst:
        movs    r6, r8, lsl #20                 @ Get offset
        beq     do_DataAbort                    @ zero -> no fixup
+       str     r9, [sp, #-4]!
        and     r9, r8, #15 << 16               @ Extract 'n' from instruction
        ldr     r7, [r2, r9, lsr #14]           @ Get register 'Rn'
        tst     r8, #1 << 23                    @ Check U bit
        subne   r7, r7, r6, lsr #20             @ Undo increment
        addeq   r7, r7, r6, lsr #20             @ Undo decrement
        str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
+       ldr     r9, [sp], #4
        b       do_DataAbort
 
 .data_arm_lateldrprereg:
@@ -115,6 +124,7 @@ ENTRY(v4t_late_abort)
 .data_arm_lateldrpostreg:
        and     r7, r8, #15                     @ Extract 'm' from instruction
        ldr     r6, [r2, r7, lsl #2]            @ Get register 'Rm'
+       str     r9, [sp, #-4]!
        mov     r9, r8, lsr #7                  @ get shift count
        ands    r9, r9, #31
        and     r7, r8, #0x70                   @ get shift type
@@ -126,33 +136,33 @@ ENTRY(v4t_late_abort)
        b       .data_arm_apply_r6_and_rn
        b       .data_arm_apply_r6_and_rn       @ 1: LSL #0
        nop
-       b       .data_unknown                   @ 2: MUL?
+       b       .data_unknown_r9                @ 2: MUL?
        nop
-       b       .data_unknown                   @ 3: MUL?
+       b       .data_unknown_r9                @ 3: MUL?
        nop
        mov     r6, r6, lsr r9                  @ 4: LSR #!0
        b       .data_arm_apply_r6_and_rn
        mov     r6, r6, lsr #32                 @ 5: LSR #32
        b       .data_arm_apply_r6_and_rn
-       b       .data_unknown                   @ 6: MUL?
+       b       .data_unknown_r9                @ 6: MUL?
        nop
-       b       .data_unknown                   @ 7: MUL?
+       b       .data_unknown_r9                @ 7: MUL?
        nop
        mov     r6, r6, asr r9                  @ 8: ASR #!0
        b       .data_arm_apply_r6_and_rn
        mov     r6, r6, asr #32                 @ 9: ASR #32
        b       .data_arm_apply_r6_and_rn
-       b       .data_unknown                   @ A: MUL?
+       b       .data_unknown_r9                @ A: MUL?
        nop
-       b       .data_unknown                   @ B: MUL?
+       b       .data_unknown_r9                @ B: MUL?
        nop
        mov     r6, r6, ror r9                  @ C: ROR #!0
        b       .data_arm_apply_r6_and_rn
        mov     r6, r6, rrx                     @ D: RRX
        b       .data_arm_apply_r6_and_rn
-       b       .data_unknown                   @ E: MUL?
+       b       .data_unknown_r9                @ E: MUL?
        nop
-       b       .data_unknown                   @ F: MUL?
+       b       .data_unknown_r9                @ F: MUL?
 
 .data_thumb_abort:
        ldrh    r8, [r4]                        @ read instruction
@@ -190,6 +200,7 @@ ENTRY(v4t_late_abort)
 .data_thumb_pushpop:
        tst     r8, #1 << 10
        beq     .data_unknown
+       str     r9, [sp, #-4]!
        and     r6, r8, #0x55                   @ hweight8(r8) + R bit
        and     r9, r8, #0xaa
        add     r6, r6, r9, lsr #1
@@ -204,9 +215,11 @@ ENTRY(v4t_late_abort)
        addeq   r7, r7, r6, lsl #2              @ increment SP if PUSH
        subne   r7, r7, r6, lsl #2              @ decrement SP if POP
        str     r7, [r2, #13 << 2]
+       ldr     r9, [sp], #4
        b       do_DataAbort
 
 .data_thumb_ldmstm:
+       str     r9, [sp, #-4]!
        and     r6, r8, #0x55                   @ hweight8(r8)
        and     r9, r8, #0xaa
        add     r6, r6, r9, lsr #1
@@ -219,4 +232,5 @@ ENTRY(v4t_late_abort)
        and     r6, r6, #15                     @ number of regs to transfer
        sub     r7, r7, r6, lsl #2              @ always decrement
        str     r7, [r2, r9, lsr #6]
+       ldr     r9, [sp], #4
        b       do_DataAbort
index ab4f74536057538ac5d8cc06930b8a04f103bcad..ab7710002ba60e99287beb41e689e3ae4d148d6e 100644 (file)
@@ -1167,7 +1167,7 @@ static int __init dma_debug_do_init(void)
        dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
        return 0;
 }
-fs_initcall(dma_debug_do_init);
+core_initcall(dma_debug_do_init);
 
 #ifdef CONFIG_ARM_DMA_USE_IOMMU
 
index f6d333f09bfe338a312fed4a246a82814d1311b7..8dea61640cc1a5e09332ad7ebf777773c9b38cc9 100644 (file)
@@ -96,7 +96,7 @@ ENTRY(cpu_cm7_proc_fin)
        ret     lr
 ENDPROC(cpu_cm7_proc_fin)
 
-       .section ".text.init", #alloc, #execinstr
+       .section ".init.text", #alloc, #execinstr
 
 __v7m_cm7_setup:
        mov     r8, #(V7M_SCB_CCR_DC | V7M_SCB_CCR_IC| V7M_SCB_CCR_BP)
index 30398dbc940a2218a2e9d792cb10b463a2d194c0..969ef880d234e3b340713948eb2e9aec8ba0b3a3 100644 (file)
@@ -915,7 +915,7 @@ config RANDOMIZE_BASE
 
 config RANDOMIZE_MODULE_REGION_FULL
        bool "Randomize the module region independently from the core kernel"
-       depends on RANDOMIZE_BASE
+       depends on RANDOMIZE_BASE && !DYNAMIC_FTRACE
        default y
        help
          Randomizes the location of the module region without considering the
index cfbdf02ef5667683e603f3669308a81c7212c6b2..101794f5ce1008b7ff007fbfc7fa23d9e63bae67 100644 (file)
@@ -190,6 +190,7 @@ config ARCH_THUNDER
 
 config ARCH_UNIPHIER
        bool "Socionext UniPhier SoC Family"
+       select ARCH_HAS_RESET_CONTROLLER
        select PINCTRL
        help
          This enables support for Socionext UniPhier SoC family.
index ab51aed6b6c18eb362f8dc65621f932bed0dc7b8..3635b8662724569d3338ebb620d603c644fe38b7 100644 (file)
@@ -15,7 +15,7 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 GZFLAGS                :=-9
 
 ifneq ($(CONFIG_RELOCATABLE),)
-LDFLAGS_vmlinux                += -pie -Bsymbolic
+LDFLAGS_vmlinux                += -pie -shared -Bsymbolic
 endif
 
 ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
index 334271a25f70b329d5aed75205ff46c02baabf62..7d3a2acc6a553471d66a2bd71ce53e8c36e10aeb 100644 (file)
                #address-cells = <3>;
                #size-cells = <2>;
                dma-coherent;
-               ranges = <0x01000000 0x00 0x5f800000 0x00 0x5f800000 0x0 0x00800000>,
+               ranges = <0x01000000 0x00 0x00000000 0x00 0x5f800000 0x0 0x00800000>,
                         <0x02000000 0x00 0x50000000 0x00 0x50000000 0x0 0x08000000>,
                         <0x42000000 0x40 0x00000000 0x40 0x00000000 0x1 0x00000000>;
                #interrupt-cells = <1>;
index 123a58b29cbdc13687f196339cc3d60c96512e8f..f0b857d6d73cc9595504b266f9cf197d9b1be5be 100644 (file)
@@ -76,7 +76,7 @@
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x1010000>;
                                local-timer-stop;
-                               entry-latency-us = <300>;
+                               entry-latency-us = <400>;
                                exit-latency-us = <1200>;
                                min-residency-us = <2500>;
                        };
index 007be826efcea9ef8c49a359c8d5a79ec7c738e9..26aaa6a7670f10b3f8cba5ea91bc214c4ba7241b 100644 (file)
@@ -76,7 +76,7 @@
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x1010000>;
                                local-timer-stop;
-                               entry-latency-us = <300>;
+                               entry-latency-us = <400>;
                                exit-latency-us = <1200>;
                                min-residency-us = <2500>;
                        };
index a7270eff6939bc677a16cc90646d5ab4d48b4fa4..6e154d948a80b9fa4e79739fff85ed6fb65dc092 100644 (file)
@@ -76,7 +76,7 @@
                                compatible = "arm,idle-state";
                                arm,psci-suspend-param = <0x1010000>;
                                local-timer-stop;
-                               entry-latency-us = <300>;
+                               entry-latency-us = <400>;
                                exit-latency-us = <1200>;
                                min-residency-us = <2500>;
                        };
index 2d7872a36b91232c1007358dfdea212052dac0b1..b09f3bc5c6c16fad4a3491dd094119002845bbef 100644 (file)
                nand-ecc-mode = "hw";
                nand-ecc-strength = <8>;
                nand-ecc-step-size = <512>;
+               nand-bus-width = <16>;
+               brcm,nand-oob-sector-size = <16>;
                #address-cells = <1>;
                #size-cells = <1>;
        };
index 220ac7057d1284fa97d5ccf1787e09a2aafd60a4..97d331ec250013ba7c1d0d7b1b9de36881fe5ee4 100644 (file)
                             <1 14 0xf08>, /* Physical Non-Secure PPI */
                             <1 11 0xf08>, /* Virtual PPI */
                             <1 10 0xf08>; /* Hypervisor PPI */
+               fsl,erratum-a008585;
        };
 
        pmu {
index 337da90bd7dade6df0d74d49a9794b6b20cc8510..7f0dc13b4087f5a346fcb60e7ab40080d74c5500 100644 (file)
                             <1 14 4>, /* Physical Non-Secure PPI, active-low */
                             <1 11 4>, /* Virtual PPI, active-low */
                             <1 10 4>; /* Hypervisor PPI, active-low */
+               fsl,erratum-a008585;
        };
 
        pmu {
index c4762538ec0100dadfc8876f4f749d3b7bdc3a34..e9bd5879346499748b0cf8b39f6d921b31bede1c 100644 (file)
                                status = "disabled";
                        };
 
-                       nb_perih_clk: nb-periph-clk@13000{
+                       nb_periph_clk: nb-periph-clk@13000 {
                                compatible = "marvell,armada-3700-periph-clock-nb";
                                reg = <0x13000 0x100>;
                                clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
                                #clock-cells = <1>;
                        };
 
-                       sb_perih_clk: sb-periph-clk@18000{
+                       sb_periph_clk: sb-periph-clk@18000 {
                                compatible = "marvell,armada-3700-periph-clock-sb";
                                reg = <0x18000 0x100>;
                                clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
index e5e3ed678b6f1d37ecb71ff27d4135fb483dbd8f..602e2c2e9a4dd13a4d892dffa3dcd141b71d89bc 100644 (file)
                                #address-cells = <0x1>;
                                #size-cells = <0x0>;
                                cell-index = <1>;
-                               clocks = <&cpm_syscon0 0 3>;
+                               clocks = <&cpm_syscon0 1 21>;
                                status = "disabled";
                        };
 
index 842fb333285c97e558ebc4f15556dfab327b73e7..6bf9e241179b7dc518f81b6d840b36c8b97b2a82 100644 (file)
                                reg = <0x700600 0x50>;
                                #address-cells = <0x1>;
                                #size-cells = <0x0>;
-                               cell-index = <1>;
-                               clocks = <&cps_syscon0 0 3>;
+                               cell-index = <3>;
+                               clocks = <&cps_syscon0 1 21>;
                                status = "disabled";
                        };
 
                                reg = <0x700680 0x50>;
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               cell-index = <2>;
+                               cell-index = <4>;
                                clocks = <&cps_syscon0 1 21>;
                                status = "disabled";
                        };
index 46cdddfcea6c43ad30518d359babe7e094b943ac..e5eeca2c24565a76b10c64183e5d143ccbed810a 100644 (file)
        cap-mmc-highspeed;
        clock-frequency = <150000000>;
        disable-wp;
-       keep-power-in-suspend;
        non-removable;
        num-slots = <1>;
        vmmc-supply = <&vcc_io>;
                        };
 
                        vcc_sd: SWITCH_REG1 {
-                               regulator-always-on;
-                               regulator-boot-on;
                                regulator-name = "vcc_sd";
                        };
 
index 5797933ef80e68454fca1eb5c8ed03dec566f434..ea0a8eceefd467968ce9f30c9e875481e4126345 100644 (file)
                gpio = <&gpio3 11 GPIO_ACTIVE_LOW>;
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <3300000>;
-               regulator-always-on;
-               regulator-boot-on;
                vin-supply = <&vcc_io>;
        };
 
        bus-width = <8>;
        cap-mmc-highspeed;
        disable-wp;
-       keep-power-in-suspend;
        mmc-pwrseq = <&emmc_pwrseq>;
        mmc-hs200-1_2v;
        mmc-hs200-1_8v;
        clock-freq-min-max = <400000 50000000>;
        cap-sd-highspeed;
        card-detect-delay = <200>;
-       keep-power-in-suspend;
        num-slots = <1>;
        pinctrl-names = "default";
        pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
index b65c193dc64effabd9d50f00a2ea176dd083dabe..7afbfb0f96a3cc6459b709b623c916650d12bc49 100644 (file)
                ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x600000
                          0x81000000 0x0 0xfa600000 0x0 0xfa600000 0x0 0x100000>;
                resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
-                        <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
-               reset-names = "core", "mgmt", "mgmt-sticky", "pipe";
+                        <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>,
+                        <&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>,
+                        <&cru SRST_A_PCIE>;
+               reset-names = "core", "mgmt", "mgmt-sticky", "pipe",
+                             "pm", "pclk", "aclk";
                status = "disabled";
 
                pcie0_intc: interrupt-controller {
index 08fd7cf7769cfd075b324c212c7aacddd67f48a1..56a1b2e92cf32e804c9a71abbf8308e8c8168526 100644 (file)
                        reg = <0x59801000 0x400>;
                };
 
-               mioctrl@59810000 {
-                       compatible = "socionext,uniphier-mioctrl",
+               sdctrl@59810000 {
+                       compatible = "socionext,uniphier-ld20-sdctrl",
                                     "simple-mfd", "syscon";
                        reg = <0x59810000 0x800>;
 
-                       mio_clk: clock {
-                               compatible = "socionext,uniphier-ld20-mio-clock";
+                       sd_clk: clock {
+                               compatible = "socionext,uniphier-ld20-sd-clock";
                                #clock-cells = <1>;
                        };
 
-                       mio_rst: reset {
-                               compatible = "socionext,uniphier-ld20-mio-reset";
+                       sd_rst: reset {
+                               compatible = "socionext,uniphier-ld20-sd-reset";
                                #reset-cells = <1>;
                        };
                };
index 39feb85a6931093b064fa548b1778808186d0924..6e1cb8c5af4d6465e81fbdce2e2bd61920cb41e9 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_ALTERNATIVE_H
 #define __ASM_ALTERNATIVE_H
 
-#include <asm/cpufeature.h>
+#include <asm/cpucaps.h>
 #include <asm/insn.h>
 
 #ifndef __ASSEMBLY__
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
new file mode 100644 (file)
index 0000000..87b4465
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/arm64/include/asm/cpucaps.h
+ *
+ * Copyright (C) 2016 ARM Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_CPUCAPS_H
+#define __ASM_CPUCAPS_H
+
+#define ARM64_WORKAROUND_CLEAN_CACHE           0
+#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE   1
+#define ARM64_WORKAROUND_845719                        2
+#define ARM64_HAS_SYSREG_GIC_CPUIF             3
+#define ARM64_HAS_PAN                          4
+#define ARM64_HAS_LSE_ATOMICS                  5
+#define ARM64_WORKAROUND_CAVIUM_23154          6
+#define ARM64_WORKAROUND_834220                        7
+#define ARM64_HAS_NO_HW_PREFETCH               8
+#define ARM64_HAS_UAO                          9
+#define ARM64_ALT_PAN_NOT_UAO                  10
+#define ARM64_HAS_VIRT_HOST_EXTN               11
+#define ARM64_WORKAROUND_CAVIUM_27456          12
+#define ARM64_HAS_32BIT_EL0                    13
+#define ARM64_HYP_OFFSET_LOW                   14
+#define ARM64_MISMATCHED_CACHE_LINE_SIZE       15
+
+#define ARM64_NCAPS                            16
+
+#endif /* __ASM_CPUCAPS_H */
index 758d74fedfad9bafe86835a56272deebf705e591..0bc0b1de90c452b369c8562e252d841bb9590a90 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/jump_label.h>
 
+#include <asm/cpucaps.h>
 #include <asm/hwcap.h>
 #include <asm/sysreg.h>
 
 #define MAX_CPU_FEATURES       (8 * sizeof(elf_hwcap))
 #define cpu_feature(x)         ilog2(HWCAP_ ## x)
 
-#define ARM64_WORKAROUND_CLEAN_CACHE           0
-#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE   1
-#define ARM64_WORKAROUND_845719                        2
-#define ARM64_HAS_SYSREG_GIC_CPUIF             3
-#define ARM64_HAS_PAN                          4
-#define ARM64_HAS_LSE_ATOMICS                  5
-#define ARM64_WORKAROUND_CAVIUM_23154          6
-#define ARM64_WORKAROUND_834220                        7
-#define ARM64_HAS_NO_HW_PREFETCH               8
-#define ARM64_HAS_UAO                          9
-#define ARM64_ALT_PAN_NOT_UAO                  10
-#define ARM64_HAS_VIRT_HOST_EXTN               11
-#define ARM64_WORKAROUND_CAVIUM_27456          12
-#define ARM64_HAS_32BIT_EL0                    13
-#define ARM64_HYP_OFFSET_LOW                   14
-#define ARM64_MISMATCHED_CACHE_LINE_SIZE       15
-
-#define ARM64_NCAPS                            16
-
 #ifndef __ASSEMBLY__
 
 #include <linux/kernel.h>
@@ -94,7 +76,7 @@ struct arm64_cpu_capabilities {
        u16 capability;
        int def_scope;                  /* default scope */
        bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
-       void (*enable)(void *);         /* Called on all active CPUs */
+       int (*enable)(void *);          /* Called on all active CPUs */
        union {
                struct {        /* To be used for erratum handling only */
                        u32 midr_model;
index db0563c23482d52175bf6c22f733410797122e36..f7865dd9d86854760e69ea71d30452625d6713ec 100644 (file)
@@ -18,6 +18,9 @@
 #ifndef __ASM_EXEC_H
 #define __ASM_EXEC_H
 
+#include <linux/sched.h>
+
 extern unsigned long arch_align_stack(unsigned long sp);
+void uao_thread_switch(struct task_struct *next);
 
 #endif /* __ASM_EXEC_H */
index 18f746551bf632cc88a3a406359463e9d49340eb..ec3553eb9349093a9c7675f7fbe4de38dba396c7 100644 (file)
@@ -54,6 +54,7 @@ extern char __kvm_hyp_vector[];
 extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
+extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
index fd9d5fd788f5f1df75febd7849bc89bc15eaf144..f5ea0ba70f077479ea9b2f4b1cb2fd077e9e20e3 100644 (file)
@@ -178,11 +178,6 @@ static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV);
 }
 
-static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
-{
-       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR);
-}
-
 static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SSE);
@@ -203,6 +198,12 @@ static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW);
 }
 
+static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR) ||
+               kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
+}
+
 static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_CM);
index bd94e67667599dc1ce499ab30de2cca91f4e97be..e5050388e062209868bac64cab1740ece15b3e13 100644 (file)
@@ -62,6 +62,9 @@ struct kvm_arch {
        /* VTTBR value associated with above pgd and vmid */
        u64    vttbr;
 
+       /* The last vcpu id that ran on each physical CPU */
+       int __percpu *last_vcpu_ran;
+
        /* The maximum number of vCPUs depends on the used GIC model */
        int max_vcpus;
 
index a79b969c26fca7dcd73e06c4bfc36c6519cb646b..6f72fe8b0e3ee477a076fa5f9ef02d13c3d8eef3 100644 (file)
@@ -128,7 +128,7 @@ static inline unsigned long __kern_hyp_va(unsigned long v)
        return v;
 }
 
-#define kern_hyp_va(v)         (typeof(v))(__kern_hyp_va((unsigned long)(v)))
+#define kern_hyp_va(v)         ((typeof(v))(__kern_hyp_va((unsigned long)(v))))
 
 /*
  * We currently only support a 40bit IPA.
index 23acc00be32d019a9f0f71b75153b5b32996b083..fc756e22c84cd718278d4f0ba8ebc6a32ff4739e 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <linux/stringify.h>
 #include <asm/alternative.h>
-#include <asm/cpufeature.h>
 
 #ifdef __ASSEMBLER__
 
index ba62df8c6e3540f8db0dcd86c26e4a9dbafb2a05..b71086d251954f7b72837899346525322dc5d724 100644 (file)
@@ -217,7 +217,7 @@ static inline void *phys_to_virt(phys_addr_t x)
 #define _virt_addr_valid(kaddr)        pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 #else
 #define __virt_to_pgoff(kaddr) (((u64)(kaddr) & ~PAGE_OFFSET) / PAGE_SIZE * sizeof(struct page))
-#define __page_to_voff(kaddr)  (((u64)(page) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page))
+#define __page_to_voff(page)   (((u64)(page) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page))
 
 #define page_to_virt(page)     ((void *)((__page_to_voff(page)) | PAGE_OFFSET))
 #define virt_to_page(vaddr)    ((struct page *)((__virt_to_pgoff(vaddr)) | VMEMMAP_START))
index e12af6754634b3d2aa031ae23ce25228dc766cfb..06ff7fd9e81feab27bb67f1a4af971ddc0ebf4cc 100644 (file)
@@ -17,6 +17,7 @@
 #define __ASM_MODULE_H
 
 #include <asm-generic/module.h>
+#include <asm/memory.h>
 
 #define MODULE_ARCH_VERMAGIC   "aarch64"
 
@@ -32,6 +33,10 @@ u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
                          Elf64_Sym *sym);
 
 #ifdef CONFIG_RANDOMIZE_BASE
+#ifdef CONFIG_MODVERSIONS
+#define ARCH_RELOCATES_KCRCTAB
+#define reloc_start            (kimage_vaddr - KIMAGE_VADDR)
+#endif
 extern u64 module_alloc_base;
 #else
 #define module_alloc_base      ((u64)_etext - MODULES_VSIZE)
index 2fee2f59288c94d70814771ed06fced11ede369d..5394c8405e6604bf612fd0c639c1f15a30d0f7d9 100644 (file)
@@ -44,48 +44,44 @@ static inline unsigned long __percpu_##op(void *ptr,                        \
                                                                        \
        switch (size) {                                                 \
        case 1:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_1\n"                  \
-                       "ldxrb    %w[ret], %[ptr]\n"                    \
+               asm ("//__per_cpu_" #op "_1\n"                          \
+               "1:     ldxrb     %w[ret], %[ptr]\n"                    \
                        #asm_op " %w[ret], %w[ret], %w[val]\n"          \
-                       "stxrb    %w[loop], %w[ret], %[ptr]\n"          \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr] "+Q"(*(u8 *)ptr)                        \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxrb     %w[loop], %w[ret], %[ptr]\n"          \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr] "+Q"(*(u8 *)ptr)                                \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        case 2:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_2\n"                  \
-                       "ldxrh    %w[ret], %[ptr]\n"                    \
+               asm ("//__per_cpu_" #op "_2\n"                          \
+               "1:     ldxrh     %w[ret], %[ptr]\n"                    \
                        #asm_op " %w[ret], %w[ret], %w[val]\n"          \
-                       "stxrh    %w[loop], %w[ret], %[ptr]\n"          \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr]  "+Q"(*(u16 *)ptr)                      \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxrh     %w[loop], %w[ret], %[ptr]\n"          \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr]  "+Q"(*(u16 *)ptr)                              \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        case 4:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_4\n"                  \
-                       "ldxr     %w[ret], %[ptr]\n"                    \
+               asm ("//__per_cpu_" #op "_4\n"                          \
+               "1:     ldxr      %w[ret], %[ptr]\n"                    \
                        #asm_op " %w[ret], %w[ret], %w[val]\n"          \
-                       "stxr     %w[loop], %w[ret], %[ptr]\n"          \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr] "+Q"(*(u32 *)ptr)                       \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxr      %w[loop], %w[ret], %[ptr]\n"          \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr] "+Q"(*(u32 *)ptr)                               \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        case 8:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_8\n"                  \
-                       "ldxr     %[ret], %[ptr]\n"                     \
+               asm ("//__per_cpu_" #op "_8\n"                          \
+               "1:     ldxr      %[ret], %[ptr]\n"                     \
                        #asm_op " %[ret], %[ret], %[val]\n"             \
-                       "stxr     %w[loop], %[ret], %[ptr]\n"           \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr] "+Q"(*(u64 *)ptr)                       \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxr      %w[loop], %[ret], %[ptr]\n"           \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr] "+Q"(*(u64 *)ptr)                               \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        default:                                                        \
                BUILD_BUG();                                            \
@@ -150,44 +146,40 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
 
        switch (size) {
        case 1:
-               do {
-                       asm ("//__percpu_xchg_1\n"
-                       "ldxrb %w[ret], %[ptr]\n"
-                       "stxrb %w[loop], %w[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u8 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_1\n"
+               "1:     ldxrb   %w[ret], %[ptr]\n"
+               "       stxrb   %w[loop], %w[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u8 *)ptr)
+               : [val] "r" (val));
                break;
        case 2:
-               do {
-                       asm ("//__percpu_xchg_2\n"
-                       "ldxrh %w[ret], %[ptr]\n"
-                       "stxrh %w[loop], %w[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u16 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_2\n"
+               "1:     ldxrh   %w[ret], %[ptr]\n"
+               "       stxrh   %w[loop], %w[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u16 *)ptr)
+               : [val] "r" (val));
                break;
        case 4:
-               do {
-                       asm ("//__percpu_xchg_4\n"
-                       "ldxr %w[ret], %[ptr]\n"
-                       "stxr %w[loop], %w[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u32 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_4\n"
+               "1:     ldxr    %w[ret], %[ptr]\n"
+               "       stxr    %w[loop], %w[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u32 *)ptr)
+               : [val] "r" (val));
                break;
        case 8:
-               do {
-                       asm ("//__percpu_xchg_8\n"
-                       "ldxr %[ret], %[ptr]\n"
-                       "stxr %w[loop], %[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u64 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_8\n"
+               "1:     ldxr    %[ret], %[ptr]\n"
+               "       stxr    %w[loop], %[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u64 *)ptr)
+               : [val] "r" (val));
                break;
        default:
                BUILD_BUG();
index 2065f46fa7407deb4d43e7dc8783ca8667759500..38b6a2b49d6895dbd7904a27792520514d445044 100644 (file)
 #define        ARMV8_PMU_EVTYPE_MASK   0xc800ffff      /* Mask for writable bits */
 #define        ARMV8_PMU_EVTYPE_EVENT  0xffff          /* Mask for EVENT bits */
 
-#define ARMV8_PMU_EVTYPE_EVENT_SW_INCR 0       /* Software increment event */
+/*
+ * PMUv3 event types: required events
+ */
+#define ARMV8_PMUV3_PERFCTR_SW_INCR                            0x00
+#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL                   0x03
+#define ARMV8_PMUV3_PERFCTR_L1D_CACHE                          0x04
+#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED                                0x10
+#define ARMV8_PMUV3_PERFCTR_CPU_CYCLES                         0x11
+#define ARMV8_PMUV3_PERFCTR_BR_PRED                            0x12
 
 /*
  * Event filters for PMUv3
index df2e53d3a96959430568e8c23509f28cbf8c9142..60e34824e18c96b06c02930961c8ce51b82a90e2 100644 (file)
@@ -188,8 +188,8 @@ static inline void spin_lock_prefetch(const void *ptr)
 
 #endif
 
-void cpu_enable_pan(void *__unused);
-void cpu_enable_uao(void *__unused);
-void cpu_enable_cache_maint_trap(void *__unused);
+int cpu_enable_pan(void *__unused);
+int cpu_enable_uao(void *__unused);
+int cpu_enable_cache_maint_trap(void *__unused);
 
 #endif /* __ASM_PROCESSOR_H */
index e8d46e8e60791a8e3a3b785563e8949b8c0007ec..6c80b3699cb8a18c076634f710e031a5b3505647 100644 (file)
@@ -286,7 +286,7 @@ asm(
 
 #define write_sysreg_s(v, r) do {                                      \
        u64 __val = (u64)v;                                             \
-       asm volatile("msr_s " __stringify(r) ", %0" : : "rZ" (__val));  \
+       asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \
 } while (0)
 
 static inline void config_sctlr_el1(u32 clear, u32 set)
index bcaf6fba1b65bd559359c35e43a43339051c5cfe..55d0adbf65098a78241d45038d1a57f642a7992e 100644 (file)
@@ -21,6 +21,7 @@
 /*
  * User space memory access functions
  */
+#include <linux/bitops.h>
 #include <linux/kasan-checks.h>
 #include <linux/string.h>
 #include <linux/thread_info.h>
@@ -102,6 +103,13 @@ static inline void set_fs(mm_segment_t fs)
        flag;                                                           \
 })
 
+/*
+ * When dealing with data aborts or instruction traps we may end up with
+ * a tagged userland pointer. Clear the tag to get a sane pointer to pass
+ * on to access_ok(), for instance.
+ */
+#define untagged_addr(addr)            sign_extend64(addr, 55)
+
 #define access_ok(type, addr, size)    __range_ok(addr, size)
 #define user_addr_max                  get_fs
 
index 42ffdb54e162d64164ab9f515d1ce21a379fb3d7..b0988bb1bf648e0e322d1112880fedab706c6f32 100644 (file)
@@ -280,35 +280,43 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table)
 /*
  * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
  */
-#define __user_swpX_asm(data, addr, res, temp, B)              \
+
+/* Arbitrary constant to ensure forward-progress of the LL/SC loop */
+#define __SWP_LL_SC_LOOPS      4
+
+#define __user_swpX_asm(data, addr, res, temp, temp2, B)       \
        __asm__ __volatile__(                                   \
+       "       mov             %w3, %w7\n"                     \
        ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN,    \
                    CONFIG_ARM64_PAN)                           \
-       "0:     ldxr"B"         %w2, [%3]\n"                    \
-       "1:     stxr"B"         %w0, %w1, [%3]\n"               \
+       "0:     ldxr"B"         %w2, [%4]\n"                    \
+       "1:     stxr"B"         %w0, %w1, [%4]\n"               \
        "       cbz             %w0, 2f\n"                      \
-       "       mov             %w0, %w4\n"                     \
+       "       sub             %w3, %w3, #1\n"                 \
+       "       cbnz            %w3, 0b\n"                      \
+       "       mov             %w0, %w5\n"                     \
        "       b               3f\n"                           \
        "2:\n"                                                  \
        "       mov             %w1, %w2\n"                     \
        "3:\n"                                                  \
        "       .pushsection     .fixup,\"ax\"\n"               \
        "       .align          2\n"                            \
-       "4:     mov             %w0, %w5\n"                     \
+       "4:     mov             %w0, %w6\n"                     \
        "       b               3b\n"                           \
        "       .popsection"                                    \
        _ASM_EXTABLE(0b, 4b)                                    \
        _ASM_EXTABLE(1b, 4b)                                    \
        ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,    \
                CONFIG_ARM64_PAN)                               \
-       : "=&r" (res), "+r" (data), "=&r" (temp)                \
-       : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)              \
+       : "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \
+       : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT),             \
+         "i" (__SWP_LL_SC_LOOPS)                               \
        : "memory")
 
-#define __user_swp_asm(data, addr, res, temp) \
-       __user_swpX_asm(data, addr, res, temp, "")
-#define __user_swpb_asm(data, addr, res, temp) \
-       __user_swpX_asm(data, addr, res, temp, "b")
+#define __user_swp_asm(data, addr, res, temp, temp2) \
+       __user_swpX_asm(data, addr, res, temp, temp2, "")
+#define __user_swpb_asm(data, addr, res, temp, temp2) \
+       __user_swpX_asm(data, addr, res, temp, temp2, "b")
 
 /*
  * Bit 22 of the instruction encoding distinguishes between
@@ -328,12 +336,12 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
        }
 
        while (1) {
-               unsigned long temp;
+               unsigned long temp, temp2;
 
                if (type == TYPE_SWPB)
-                       __user_swpb_asm(*data, address, res, temp);
+                       __user_swpb_asm(*data, address, res, temp, temp2);
                else
-                       __user_swp_asm(*data, address, res, temp);
+                       __user_swp_asm(*data, address, res, temp, temp2);
 
                if (likely(res != -EAGAIN) || signal_pending(current))
                        break;
index 0150394f4cabf2f34b27c88ee6575b0a9b7b4489..b75e917aac464290b523e1b3cc8cd7822364eeb7 100644 (file)
@@ -39,10 +39,11 @@ has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry,
                (arm64_ftr_reg_ctrel0.sys_val & arm64_ftr_reg_ctrel0.strict_mask);
 }
 
-static void cpu_enable_trap_ctr_access(void *__unused)
+static int cpu_enable_trap_ctr_access(void *__unused)
 {
        /* Clear SCTLR_EL1.UCT */
        config_sctlr_el1(SCTLR_EL1_UCT, 0);
+       return 0;
 }
 
 #define MIDR_RANGE(model, min, max) \
index d577f263cc4aa46057e3b1ac210e23038e7d0e01..c02504ea304b701e1cc077388380079ac60f37d2 100644 (file)
@@ -19,7 +19,9 @@
 #define pr_fmt(fmt) "CPU features: " fmt
 
 #include <linux/bsearch.h>
+#include <linux/cpumask.h>
 #include <linux/sort.h>
+#include <linux/stop_machine.h>
 #include <linux/types.h>
 #include <asm/cpu.h>
 #include <asm/cpufeature.h>
@@ -941,7 +943,13 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
 {
        for (; caps->matches; caps++)
                if (caps->enable && cpus_have_cap(caps->capability))
-                       on_each_cpu(caps->enable, NULL, true);
+                       /*
+                        * Use stop_machine() as it schedules the work allowing
+                        * us to modify PSTATE, instead of on_each_cpu() which
+                        * uses an IPI, giving us a PSTATE that disappears when
+                        * we return.
+                        */
+                       stop_machine(caps->enable, NULL, cpu_online_mask);
 }
 
 /*
index 427f6d3f084c30aeb35908155aae3af9aacadf2e..332e33193ccf1575727dfc8883644a5cfabd0e08 100644 (file)
@@ -586,8 +586,9 @@ CPU_LE(     movk    x0, #0x30d0, lsl #16    )       // Clear EE and E0E on LE systems
        b.lt    4f                              // Skip if no PMU present
        mrs     x0, pmcr_el0                    // Disable debug access traps
        ubfx    x0, x0, #11, #5                 // to EL2 and allow access to
-       msr     mdcr_el2, x0                    // all PMU counters from EL1
 4:
+       csel    x0, xzr, x0, lt                 // all PMU counters from EL1
+       msr     mdcr_el2, x0                    // (if they exist)
 
        /* Stage-2 translation */
        msr     vttbr_el2, xzr
index a9310a69fffd4d453b760a15d16cc8e9cd1a90e8..57ae9d9ed9bb666e5bd20698f9dce2d1f25d731f 100644 (file)
 
 /*
  * ARMv8 PMUv3 Performance Events handling code.
- * Common event types.
+ * Common event types (some are defined in asm/perf_event.h).
  */
 
-/* Required events. */
-#define ARMV8_PMUV3_PERFCTR_SW_INCR                            0x00
-#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL                   0x03
-#define ARMV8_PMUV3_PERFCTR_L1D_CACHE                          0x04
-#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED                                0x10
-#define ARMV8_PMUV3_PERFCTR_CPU_CYCLES                         0x11
-#define ARMV8_PMUV3_PERFCTR_BR_PRED                            0x12
-
 /* At least one of the following is required. */
 #define ARMV8_PMUV3_PERFCTR_INST_RETIRED                       0x08
 #define ARMV8_PMUV3_PERFCTR_INST_SPEC                          0x1B
index 27b2f1387df40b61b4aa059be5650d329964da6b..01753cd7d3f01d3551568d64612bd5a14843ac18 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/alternative.h>
 #include <asm/compat.h>
 #include <asm/cacheflush.h>
+#include <asm/exec.h>
 #include <asm/fpsimd.h>
 #include <asm/mmu_context.h>
 #include <asm/processor.h>
@@ -186,10 +187,19 @@ void __show_regs(struct pt_regs *regs)
        printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n",
               regs->pc, lr, regs->pstate);
        printk("sp : %016llx\n", sp);
-       for (i = top_reg; i >= 0; i--) {
+
+       i = top_reg;
+
+       while (i >= 0) {
                printk("x%-2d: %016llx ", i, regs->regs[i]);
-               if (i % 2 == 0)
-                       printk("\n");
+               i--;
+
+               if (i % 2 == 0) {
+                       pr_cont("x%-2d: %016llx ", i, regs->regs[i]);
+                       i--;
+               }
+
+               pr_cont("\n");
        }
        printk("\n");
 }
@@ -301,7 +311,7 @@ static void tls_thread_switch(struct task_struct *next)
 }
 
 /* Restore the UAO state depending on next's addr_limit */
-static void uao_thread_switch(struct task_struct *next)
+void uao_thread_switch(struct task_struct *next)
 {
        if (IS_ENABLED(CONFIG_ARM64_UAO)) {
                if (task_thread_info(next)->addr_limit == KERNEL_DS)
index b8799e7c79de51dac71c5f7485709177b7cd3b5d..1bec41b5fda3917b2ed7583663a239f25c6126bf 100644 (file)
@@ -135,7 +135,7 @@ ENTRY(_cpu_resume)
 
 #ifdef CONFIG_KASAN
        mov     x0, sp
-       bl      kasan_unpoison_remaining_stack
+       bl      kasan_unpoison_task_stack_below
 #endif
 
        ldp     x19, x20, [x29, #16]
index d3f151cfd4a1f800a58511ca0a8d10d37001b601..8507703dabe4a4cb521527456f14ba26855d5b43 100644 (file)
@@ -544,6 +544,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
                        return;
                }
                bootcpu_valid = true;
+               early_map_cpu_to_node(0, acpi_numa_get_nid(0, hwid));
                return;
        }
 
index ad734142070dcd143f3a7559ff50a044e93e95ac..bb0cd787a9d31dc4762d3a98257b3e11d8afe6f0 100644 (file)
@@ -1,8 +1,11 @@
 #include <linux/ftrace.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
+#include <asm/alternative.h>
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #include <asm/debug-monitors.h>
+#include <asm/exec.h>
 #include <asm/pgtable.h>
 #include <asm/memory.h>
 #include <asm/mmu_context.h>
@@ -49,6 +52,14 @@ void notrace __cpu_suspend_exit(void)
         */
        set_my_cpu_offset(per_cpu_offset(cpu));
 
+       /*
+        * PSTATE was not saved over suspend/resume, re-enable any detected
+        * features that might not have been set correctly.
+        */
+       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,
+                       CONFIG_ARM64_PAN));
+       uao_thread_switch(current);
+
        /*
         * Restore HW breakpoint registers to sane values
         * before debug exceptions are possibly reenabled
index 5ff020f8fb7f65cdec1d88213f0f185ef157ef33..c9986b3e0a96f9ddd0d79ad52e0d5de7841172ec 100644 (file)
@@ -428,24 +428,28 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
        force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
 }
 
-void cpu_enable_cache_maint_trap(void *__unused)
+int cpu_enable_cache_maint_trap(void *__unused)
 {
        config_sctlr_el1(SCTLR_EL1_UCI, 0);
+       return 0;
 }
 
 #define __user_cache_maint(insn, address, res)                 \
-       asm volatile (                                          \
-               "1:     " insn ", %1\n"                         \
-               "       mov     %w0, #0\n"                      \
-               "2:\n"                                          \
-               "       .pushsection .fixup,\"ax\"\n"           \
-               "       .align  2\n"                            \
-               "3:     mov     %w0, %w2\n"                     \
-               "       b       2b\n"                           \
-               "       .popsection\n"                          \
-               _ASM_EXTABLE(1b, 3b)                            \
-               : "=r" (res)                                    \
-               : "r" (address), "i" (-EFAULT) )
+       if (untagged_addr(address) >= user_addr_max())          \
+               res = -EFAULT;                                  \
+       else                                                    \
+               asm volatile (                                  \
+                       "1:     " insn ", %1\n"                 \
+                       "       mov     %w0, #0\n"              \
+                       "2:\n"                                  \
+                       "       .pushsection .fixup,\"ax\"\n"   \
+                       "       .align  2\n"                    \
+                       "3:     mov     %w0, %w2\n"             \
+                       "       b       2b\n"                   \
+                       "       .popsection\n"                  \
+                       _ASM_EXTABLE(1b, 3b)                    \
+                       : "=r" (res)                            \
+                       : "r" (address), "i" (-EFAULT) )
 
 static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
 {
index 9cc0ea784ae60a0a5086f1c5f6d129cd7d360f13..88e2f2b938f070c7570a8d76ae9ca348b1fd71e9 100644 (file)
@@ -64,6 +64,21 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
        write_sysreg(0, vttbr_el2);
 }
 
+void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
+{
+       struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
+
+       /* Switch to requested VMID */
+       write_sysreg(kvm->arch.vttbr, vttbr_el2);
+       isb();
+
+       asm volatile("tlbi vmalle1" : : );
+       dsb(nsh);
+       isb();
+
+       write_sysreg(0, vttbr_el2);
+}
+
 void __hyp_text __kvm_flush_vm_context(void)
 {
        dsb(ishst);
index f302fdb3a030b452286ed5e50e4e2ecb9c0e54fc..87e7e6608cd8a31e6913be8134b90e443df314cb 100644 (file)
@@ -597,8 +597,14 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 
                        idx = ARMV8_PMU_CYCLE_IDX;
                } else {
-                       BUG();
+                       return false;
                }
+       } else if (r->CRn == 0 && r->CRm == 9) {
+               /* PMCCNTR */
+               if (pmu_access_event_counter_el0_disabled(vcpu))
+                       return false;
+
+               idx = ARMV8_PMU_CYCLE_IDX;
        } else if (r->CRn == 14 && (r->CRm & 12) == 8) {
                /* PMEVCNTRn_EL0 */
                if (pmu_access_event_counter_el0_disabled(vcpu))
@@ -606,7 +612,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 
                idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
        } else {
-               BUG();
+               return false;
        }
 
        if (!pmu_counter_idx_valid(vcpu, idx))
index 53d9159662fe4c2cc12c810539782b5416f58bfb..0f87883748153bb3ab7cfedf090faf20e614393c 100644 (file)
@@ -29,7 +29,9 @@
 #include <linux/sched.h>
 #include <linux/highmem.h>
 #include <linux/perf_event.h>
+#include <linux/preempt.h>
 
+#include <asm/bug.h>
 #include <asm/cpufeature.h>
 #include <asm/exception.h>
 #include <asm/debug-monitors.h>
@@ -670,9 +672,17 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
 NOKPROBE_SYMBOL(do_debug_exception);
 
 #ifdef CONFIG_ARM64_PAN
-void cpu_enable_pan(void *__unused)
+int cpu_enable_pan(void *__unused)
 {
+       /*
+        * We modify PSTATE. This won't work from irq context as the PSTATE
+        * is discarded once we return from the exception.
+        */
+       WARN_ON_ONCE(in_interrupt());
+
        config_sctlr_el1(SCTLR_EL1_SPAN, 0);
+       asm(SET_PSTATE_PAN(1));
+       return 0;
 }
 #endif /* CONFIG_ARM64_PAN */
 
@@ -683,8 +693,9 @@ void cpu_enable_pan(void *__unused)
  * We need to enable the feature at runtime (instead of adding it to
  * PSR_MODE_EL1h) as the feature may not be implemented by the cpu.
  */
-void cpu_enable_uao(void *__unused)
+int cpu_enable_uao(void *__unused)
 {
        asm(SET_PSTATE_UAO(1));
+       return 0;
 }
 #endif /* CONFIG_ARM64_UAO */
index 21c489bdeb4ee03d0a126070452c92b1aca6a1b6..212c4d1e2f26df7f291270fb461abac912ce7161 100644 (file)
@@ -421,35 +421,35 @@ void __init mem_init(void)
 
        pr_notice("Virtual kernel memory layout:\n");
 #ifdef CONFIG_KASAN
-       pr_cont("    kasan   : 0x%16lx - 0x%16lx   (%6ld GB)\n",
+       pr_notice("    kasan   : 0x%16lx - 0x%16lx   (%6ld GB)\n",
                MLG(KASAN_SHADOW_START, KASAN_SHADOW_END));
 #endif
-       pr_cont("    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n",
+       pr_notice("    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n",
                MLM(MODULES_VADDR, MODULES_END));
-       pr_cont("    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n",
+       pr_notice("    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n",
                MLG(VMALLOC_START, VMALLOC_END));
-       pr_cont("      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n",
+       pr_notice("      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n",
                MLK_ROUNDUP(_text, _etext));
-       pr_cont("    .rodata : 0x%p" " - 0x%p" "   (%6ld KB)\n",
+       pr_notice("    .rodata : 0x%p" " - 0x%p" "   (%6ld KB)\n",
                MLK_ROUNDUP(__start_rodata, __init_begin));
-       pr_cont("      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n",
+       pr_notice("      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n",
                MLK_ROUNDUP(__init_begin, __init_end));
-       pr_cont("      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n",
+       pr_notice("      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n",
                MLK_ROUNDUP(_sdata, _edata));
-       pr_cont("       .bss : 0x%p" " - 0x%p" "   (%6ld KB)\n",
+       pr_notice("       .bss : 0x%p" " - 0x%p" "   (%6ld KB)\n",
                MLK_ROUNDUP(__bss_start, __bss_stop));
-       pr_cont("    fixed   : 0x%16lx - 0x%16lx   (%6ld KB)\n",
+       pr_notice("    fixed   : 0x%16lx - 0x%16lx   (%6ld KB)\n",
                MLK(FIXADDR_START, FIXADDR_TOP));
-       pr_cont("    PCI I/O : 0x%16lx - 0x%16lx   (%6ld MB)\n",
+       pr_notice("    PCI I/O : 0x%16lx - 0x%16lx   (%6ld MB)\n",
                MLM(PCI_IO_START, PCI_IO_END));
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-       pr_cont("    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n",
+       pr_notice("    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n",
                MLG(VMEMMAP_START, VMEMMAP_START + VMEMMAP_SIZE));
-       pr_cont("              0x%16lx - 0x%16lx   (%6ld MB actual)\n",
+       pr_notice("              0x%16lx - 0x%16lx   (%6ld MB actual)\n",
                MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()),
                    (unsigned long)virt_to_page(high_memory)));
 #endif
-       pr_cont("    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n",
+       pr_notice("    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n",
                MLM(__phys_to_virt(memblock_start_of_DRAM()),
                    (unsigned long)high_memory));
 
index 778a985c8a70761d8bf3337c073b76a09e50d889..4b32168cf91a0e3b99e1d899960d47fddf38ba06 100644 (file)
@@ -147,7 +147,7 @@ static int __init early_cpu_to_node(int cpu)
 
 static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
 {
-       return node_distance(from, to);
+       return node_distance(early_cpu_to_node(from), early_cpu_to_node(to));
 }
 
 static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size,
@@ -223,8 +223,11 @@ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn)
        void *nd;
        int tnid;
 
-       pr_info("Initmem setup node %d [mem %#010Lx-%#010Lx]\n",
-               nid, start_pfn << PAGE_SHIFT, (end_pfn << PAGE_SHIFT) - 1);
+       if (start_pfn < end_pfn)
+               pr_info("Initmem setup node %d [mem %#010Lx-%#010Lx]\n", nid,
+                       start_pfn << PAGE_SHIFT, (end_pfn << PAGE_SHIFT) - 1);
+       else
+               pr_info("Initmem setup node %d [<memory-less node>]\n", nid);
 
        nd_pa = memblock_alloc_try_nid(nd_size, SMP_CACHE_BYTES, nid);
        nd = __va(nd_pa);
index 8b8fe671b1a6dbf347dd4d31a7f272ef87154bcb..8d79286ee4e878044b02c963f5fb3c6deaaafb19 100644 (file)
@@ -271,7 +271,7 @@ long arch_ptrace(struct task_struct *child, long request,
                        case BFIN_MEM_ACCESS_CORE:
                        case BFIN_MEM_ACCESS_CORE_ONLY:
                                copied = access_process_vm(child, addr, &tmp,
-                                                          to_copy, 0);
+                                                          to_copy, FOLL_FORCE);
                                if (copied)
                                        break;
 
@@ -324,7 +324,8 @@ long arch_ptrace(struct task_struct *child, long request,
                        case BFIN_MEM_ACCESS_CORE:
                        case BFIN_MEM_ACCESS_CORE_ONLY:
                                copied = access_process_vm(child, addr, &data,
-                                                          to_copy, 1);
+                                                          to_copy,
+                                                          FOLL_FORCE | FOLL_WRITE);
                                break;
                        case BFIN_MEM_ACCESS_DMA:
                                if (safe_dma_memcpy(paddr, &data, to_copy))
index b5698c876fccd91c3960439753d24510ce008984..0068fd411a8473707efb4a1718e33edee0fdbb50 100644 (file)
@@ -2722,7 +2722,6 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
        err = get_user_pages((unsigned long int)(oper.indata + prev_ix),
                             noinpages,
                             0,  /* read access only for in data */
-                            0, /* no force */
                             inpages,
                             NULL);
 
@@ -2736,8 +2735,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
        if (oper.do_cipher){
                err = get_user_pages((unsigned long int)oper.cipher_outdata,
                                     nooutpages,
-                                    1, /* write access for out data */
-                                    0, /* no force */
+                                    FOLL_WRITE, /* write access for out data */
                                     outpages,
                                     NULL);
                up_read(&current->mm->mmap_sem);
@@ -3151,7 +3149,7 @@ static void print_dma_descriptors(struct cryptocop_int_operation *iop)
        printk("print_dma_descriptors start\n");
 
        printk("iop:\n");
-       printk("\tsid: 0x%lld\n", iop->sid);
+       printk("\tsid: 0x%llx\n", iop->sid);
 
        printk("\tcdesc_out: 0x%p\n", iop->cdesc_out);
        printk("\tcdesc_in: 0x%p\n", iop->cdesc_in);
index f085229cf870bc306b95df2dee4eadd9ebdd4b8b..f0df654ac6fc5ca53ffd6d6951817e92f492e0be 100644 (file)
@@ -147,7 +147,7 @@ long arch_ptrace(struct task_struct *child, long request,
                                /* The trampoline page is globally mapped, no page table to traverse.*/
                                tmp = *(unsigned long*)addr;
                        } else {
-                               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+                               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE);
 
                                if (copied != sizeof(tmp))
                                        break;
@@ -279,7 +279,7 @@ static int insn_size(struct task_struct *child, unsigned long pc)
   int opsize = 0;
 
   /* Read the opcode at pc (do what PTRACE_PEEKTEXT would do). */
-  copied = access_process_vm(child, pc, &opcode, sizeof(opcode), 0);
+  copied = access_process_vm(child, pc, &opcode, sizeof(opcode), FOLL_FORCE);
   if (copied != sizeof(opcode))
     return 0;
 
index b408fe660cf8ceab685de783220a2db991b4dfc3..3cef06875f5ca32930c06b07db027e86f362ce94 100644 (file)
@@ -31,7 +31,6 @@ struct thread_info {
        int                cpu;                 /* cpu we're on */
        int                preempt_count;       /* 0 => preemptable, <0 => BUG */
        mm_segment_t            addr_limit;
-       struct restart_block restart_block;
 };
 
 /*
@@ -44,9 +43,6 @@ struct thread_info {
        .cpu =          0,                      \
        .preempt_count = INIT_PREEMPT_COUNT,    \
        .addr_limit     = KERNEL_DS,            \
-       .restart_block  = {                     \
-               .fn = do_no_restart_syscall,    \
-       },                                      \
 }
 
 #define init_thread_info       (init_thread_union.thread_info)
index ad1f81f574e5785ee42e26219173595c1d8a66b6..7138303cbbf25dfd7fb03c6fe177199e441617ab 100644 (file)
@@ -79,7 +79,7 @@ restore_sigcontext(struct sigcontext *usc, int *pd0)
        unsigned int er0;
 
        /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+       current->restart_block.fn = do_no_restart_syscall;
 
        /* restore passed registers */
 #define COPY(r)  do { err |= get_user(regs->r, &usc->sc_##r); } while (0)
index 09f845793d12c1147bc767885673545a3bef88f3..5ed0ea92c5bfac3935b3b799607dca9b3b6086a9 100644 (file)
@@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr,
        u64 virt_addr=simple_strtoull(buf, NULL, 16);
        int ret;
 
-       ret = get_user_pages(virt_addr, 1, VM_READ, 0, NULL, NULL);
+       ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL);
        if (ret<=0) {
 #ifdef ERR_INJ_DEBUG
                printk("Virtual address %lx is not existing.\n",virt_addr);
index 6f54d511cc509a03ac079871b6979f03e6b53bc8..31aa8c0f68e14a284e0f2b088afe4c29de7daee5 100644 (file)
@@ -453,7 +453,7 @@ ia64_peek (struct task_struct *child, struct switch_stack *child_stack,
                        return 0;
                }
        }
-       copied = access_process_vm(child, addr, &ret, sizeof(ret), 0);
+       copied = access_process_vm(child, addr, &ret, sizeof(ret), FOLL_FORCE);
        if (copied != sizeof(ret))
                return -EIO;
        *val = ret;
@@ -489,7 +489,8 @@ ia64_poke (struct task_struct *child, struct switch_stack *child_stack,
                                *ia64_rse_skip_regs(krbs, regnum) = val;
                        }
                }
-       } else if (access_process_vm(child, addr, &val, sizeof(val), 1)
+       } else if (access_process_vm(child, addr, &val, sizeof(val),
+                               FOLL_FORCE | FOLL_WRITE)
                   != sizeof(val))
                return -EIO;
        return 0;
@@ -543,7 +544,8 @@ ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw,
                ret = ia64_peek(child, sw, user_rbs_end, addr, &val);
                if (ret < 0)
                        return ret;
-               if (access_process_vm(child, addr, &val, sizeof(val), 1)
+               if (access_process_vm(child, addr, &val, sizeof(val),
+                               FOLL_FORCE | FOLL_WRITE)
                    != sizeof(val))
                        return -EIO;
        }
@@ -559,7 +561,8 @@ ia64_sync_kernel_rbs (struct task_struct *child, struct switch_stack *sw,
 
        /* now copy word for word from user rbs to kernel rbs: */
        for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) {
-               if (access_process_vm(child, addr, &val, sizeof(val), 0)
+               if (access_process_vm(child, addr, &val, sizeof(val),
+                               FOLL_FORCE)
                                != sizeof(val))
                        return -EIO;
 
@@ -1156,7 +1159,8 @@ arch_ptrace (struct task_struct *child, long request,
        case PTRACE_PEEKTEXT:
        case PTRACE_PEEKDATA:
                /* read word at location addr */
-               if (access_process_vm(child, addr, &data, sizeof(data), 0)
+               if (access_process_vm(child, addr, &data, sizeof(data),
+                               FOLL_FORCE)
                    != sizeof(data))
                        return -EIO;
                /* ensure return value is not mistaken for error code */
index 51f5e9aa49016fdce8112eb72083c0b167f21df8..c145605a981ff4fbc441ffe4512a6167147f6bec 100644 (file)
@@ -493,7 +493,8 @@ unregister_all_debug_traps(struct task_struct *child)
        int i;
 
        for (i = 0; i < p->nr_trap; i++)
-               access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]), 1);
+               access_process_vm(child, p->addr[i], &p->insn[i], sizeof(p->insn[i]),
+                               FOLL_FORCE | FOLL_WRITE);
        p->nr_trap = 0;
 }
 
@@ -537,7 +538,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc)
        unsigned long next_insn, code;
        unsigned long addr = next_pc & ~3;
 
-       if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0)
+       if (access_process_vm(child, addr, &next_insn, sizeof(next_insn),
+                       FOLL_FORCE)
            != sizeof(next_insn)) {
                return -1; /* error */
        }
@@ -546,7 +548,8 @@ embed_debug_trap(struct task_struct *child, unsigned long next_pc)
        if (register_debug_trap(child, next_pc, next_insn, &code)) {
                return -1; /* error */
        }
-       if (access_process_vm(child, addr, &code, sizeof(code), 1)
+       if (access_process_vm(child, addr, &code, sizeof(code),
+                       FOLL_FORCE | FOLL_WRITE)
            != sizeof(code)) {
                return -1; /* error */
        }
@@ -562,7 +565,8 @@ withdraw_debug_trap(struct pt_regs *regs)
        addr = (regs->bpc - 2) & ~3;
        regs->bpc -= 2;
        if (unregister_debug_trap(current, addr, &code)) {
-           access_process_vm(current, addr, &code, sizeof(code), 1);
+           access_process_vm(current, addr, &code, sizeof(code),
+                   FOLL_FORCE | FOLL_WRITE);
            invalidate_cache();
        }
 }
@@ -589,7 +593,8 @@ void user_enable_single_step(struct task_struct *child)
        /* Compute next pc.  */
        pc = get_stack_long(child, PT_BPC);
 
-       if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
+       if (access_process_vm(child, pc&~3, &insn, sizeof(insn),
+                       FOLL_FORCE)
            != sizeof(insn))
                return;
 
index 55be7e3ff109056e7837d9014b74e673e9012b57..b98acd15ca22d59fce754a93ee44c4d5619804f8 100644 (file)
@@ -95,9 +95,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -105,8 +106,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -366,6 +369,7 @@ CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_A2065=y
 CONFIG_ARIADNE=y
 # CONFIG_NET_VENDOR_ARC is not set
index 365dda66b0e669a4fa59e85bb4ec4e1f924b3f04..f80dc57e6374d3cf5e001eb29ca1ed8adb3b71d0 100644 (file)
@@ -93,9 +93,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -103,8 +104,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -347,6 +350,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
index ce3cbfd16fcd91b171abc8c13ededc8cc0e8ffb9..4e16b1821fbbf0d89c91b3d0fd16b419aef29307 100644 (file)
@@ -93,9 +93,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -103,8 +104,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -356,6 +359,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_ATARILANCE=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
index 8db496a9797d2dd17eee9c6dcbd0afc810afb1be..2767bbf5ad61c18afc264590155baa789f3b427e 100644 (file)
@@ -91,9 +91,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -101,8 +102,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -346,6 +349,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
index 8314156f71490d2b554ee0909d94fdd848769a87..d13ba309265e5d979d607ba02bbbdcf7bf0d7d71 100644 (file)
@@ -93,9 +93,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -103,8 +104,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -347,6 +350,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_HPLANCE=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
index 6600270b9622a2bad488f363ff66127750a42fa0..78b5101c1aa63476ffe8294927385328f411af01 100644 (file)
@@ -92,9 +92,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -102,8 +103,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -363,6 +366,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_MACMACE=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
index 90abfe9eabba159f49e863b3e594b1088a845a09..38e5bcbd0d62eaf42c7f0d6055446efbe45fa13f 100644 (file)
@@ -102,9 +102,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -112,8 +113,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -397,6 +400,7 @@ CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_A2065=y
 CONFIG_ARIADNE=y
 CONFIG_ATARILANCE=y
index 0d502c2f73d5c6be52476eb2106144798c32c148..28687192b68e4a74ba1d9b53f1732f7130b6be92 100644 (file)
@@ -90,9 +90,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -100,8 +101,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -345,6 +348,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_MVME147_NET=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
index 5930e91fc710cfa1a07111aedb5a93225e78362b..5a5f109ab3cdeb8ad992b2234f7e26a896039510 100644 (file)
@@ -91,9 +91,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -101,8 +102,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -346,6 +349,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
index 74e3ad82eca9e509daf9268d694c57fa6a568bb6..e557c9de3fbce9c8b9b2b809610f59769d00a540 100644 (file)
@@ -91,9 +91,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -101,8 +102,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -353,6 +356,7 @@ CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_AMAZON is not set
 # CONFIG_NET_VENDOR_AMD is not set
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
index 4ba8606a4e697c16e08174dff44f6485c8f46128..c6a748a36daf53798fcf8f3f9a61cbdca133fb46 100644 (file)
@@ -88,9 +88,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -98,8 +99,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -343,6 +346,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_SUN3LANCE=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
index c6f49726a6c911d82d5ead9dd8a07cd902753f50..10d60857b9a691703f3e4297963abeb05dcc40fa 100644 (file)
@@ -88,9 +88,10 @@ CONFIG_NF_TABLES_INET=m
 CONFIG_NF_TABLES_NETDEV=m
 CONFIG_NFT_EXTHDR=m
 CONFIG_NFT_META=m
+CONFIG_NFT_NUMGEN=m
 CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
+CONFIG_NFT_SET_RBTREE=m
+CONFIG_NFT_SET_HASH=m
 CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
@@ -98,8 +99,10 @@ CONFIG_NFT_MASQ=m
 CONFIG_NFT_REDIR=m
 CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
 CONFIG_NFT_DUP_NETDEV=m
 CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
@@ -343,6 +346,7 @@ CONFIG_MACSEC=m
 CONFIG_NETCONSOLE=m
 CONFIG_NETCONSOLE_DYNAMIC=y
 CONFIG_VETH=m
+# CONFIG_NET_VENDOR_AMAZON is not set
 CONFIG_SUN3LANCE=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
index d28fa8fe26fece499884fe1c7530ca0ad5dd9af4..c598d847d56b214a653dfa09924471206e44f123 100644 (file)
@@ -114,6 +114,6 @@ static inline void __udelay(unsigned long usecs)
  */
 #define        HZSCALE         (268435456 / (1000000 / HZ))
 
-#define ndelay(n) __delay(DIV_ROUND_UP((n) * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6), 1000));
+#define ndelay(n) __delay(DIV_ROUND_UP((n) * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6), 1000))
 
 #endif /* defined(_M68K_DELAY_H) */
index fbf40d3c81239e684a6f96856d19bf0ea359d4ac..1a6bac7b076f31934d397f22c5ccac600e36b4b4 100644 (file)
@@ -263,7 +263,7 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)
 
 bootvars-y     = VMLINUX_LOAD_ADDRESS=$(load-y) \
                  VMLINUX_ENTRY_ADDRESS=$(entry-y) \
-                 PLATFORM=$(platform-y)
+                 PLATFORM="$(platform-y)"
 ifdef CONFIG_32BIT
 bootvars-y     += ADDR_BITS=32
 endif
index f604a272d91dc61e6726e6ffd98f072923ab8c9e..ffe3a1508e72c1c389749be5861c815e918b5019 100644 (file)
        fpga_regs: system-controller@1f000000 {
                compatible = "mti,malta-fpga", "syscon", "simple-mfd";
                reg = <0x1f000000 0x1000>;
+               native-endian;
 
                reboot {
                        compatible = "syscon-reboot";
                        regmap = <&fpga_regs>;
                        offset = <0x500>;
-                       mask = <0x4d>;
+                       mask = <0x42>;
                };
        };
 
index 0ea73e84544048d7c121102dbd4da8000edb3e61..d493ccbf274af0dccfcc0639d4446a0460eca284 100644 (file)
@@ -29,10 +29,20 @@ static __initdata const struct mips_machine *mach;
 static __initdata const void *mach_match_data;
 
 void __init prom_init(void)
+{
+       plat_get_fdt();
+       BUG_ON(!fdt);
+}
+
+void __init *plat_get_fdt(void)
 {
        const struct mips_machine *check_mach;
        const struct of_device_id *match;
 
+       if (fdt)
+               /* Already set up */
+               return (void *)fdt;
+
        if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) {
                /*
                 * We booted using the UHI boot protocol, so we have been
@@ -75,12 +85,6 @@ void __init prom_init(void)
                /* Retrieve the machine's FDT */
                fdt = mach->fdt;
        }
-
-       BUG_ON(!fdt);
-}
-
-void __init *plat_get_fdt(void)
-{
        return (void *)fdt;
 }
 
index 355dc25172e7a91b7ccf3c959a4a8fbd05dbf390..c05369e0b8d60352dc1833880b026e15ac09ba17 100644 (file)
@@ -63,6 +63,8 @@ do {                                                                  \
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
                                    struct mips_fpu_struct *ctx, int has_fpu,
                                    void *__user *fault_addr);
+void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
+                    struct task_struct *tsk);
 int process_fpemu_return(int sig, void __user *fault_addr,
                         unsigned long fcr31);
 int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
@@ -81,4 +83,15 @@ static inline void fpu_emulator_init_fpu(void)
                set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
 }
 
+/*
+ * Mask the FCSR Cause bits according to the Enable bits, observing
+ * that Unimplemented is always enabled.
+ */
+static inline unsigned long mask_fcr31_x(unsigned long fcr31)
+{
+       return fcr31 & (FPU_CSR_UNI_X |
+                       ((fcr31 & FPU_CSR_ALL_E) <<
+                        (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E))));
+}
+
 #endif /* _ASM_FPU_EMULATOR_H */
index 07f58cfc1ab98b2724d01630130527c0546b1126..bebec370324f4401e298bf1bbaa292666972e31c 100644 (file)
@@ -293,7 +293,10 @@ struct kvm_vcpu_arch {
        /* Host KSEG0 address of the EI/DI offset */
        void *kseg0_commpage;
 
-       u32 io_gpr;             /* GPR used as IO source/target */
+       /* Resume PC after MMIO completion */
+       unsigned long io_pc;
+       /* GPR used as IO source/target */
+       u32 io_gpr;
 
        struct hrtimer comparecount_timer;
        /* Count timer control KVM register */
@@ -315,8 +318,6 @@ struct kvm_vcpu_arch {
        /* Bitmask of pending exceptions to be cleared */
        unsigned long pending_exceptions_clr;
 
-       u32 pending_load_cause;
-
        /* Save/Restore the entryhi register when are are preempted/scheduled back in */
        unsigned long preempt_entryhi;
 
index 7dd2dd47909a3295b08ae5de56de7390c19ff6f1..df78b2ca70ebd8c6b57348f9e62f304394f4f3d0 100644 (file)
 #error Bad page size configuration for hugetlbfs!
 #endif
 
+/*
+ * Wired register bits
+ */
+#define MIPSR6_WIRED_LIMIT     (_ULCAST_(0xffff) << 16)
+#define MIPSR6_WIRED_WIRED     (_ULCAST_(0xffff) << 0)
+
 /*
  * Values used for computation of new tlb entries
  */
index ebb5c0f2f90daef7b2bcca348fb90df2b7530037..c0ae27971e3108093fdc3952969d15bb3bfd5f30 100644 (file)
@@ -75,6 +75,22 @@ do { if (cpu_has_rw_llb) {                                           \
        }                                                               \
 } while (0)
 
+/*
+ * Check FCSR for any unmasked exceptions pending set with `ptrace',
+ * clear them and send a signal.
+ */
+#define __sanitize_fcr31(next)                                         \
+do {                                                                   \
+       unsigned long fcr31 = mask_fcr31_x(next->thread.fpu.fcr31);     \
+       void __user *pc;                                                \
+                                                                       \
+       if (unlikely(fcr31)) {                                          \
+               pc = (void __user *)task_pt_regs(next)->cp0_epc;        \
+               next->thread.fpu.fcr31 &= ~fcr31;                       \
+               force_fcr31_sig(fcr31, pc, next);                       \
+       }                                                               \
+} while (0)
+
 /*
  * For newly created kernel threads switch_to() will return to
  * ret_from_kernel_thread, newly created user threads to ret_from_fork.
@@ -85,6 +101,8 @@ do { if (cpu_has_rw_llb) {                                           \
 do {                                                                   \
        __mips_mt_fpaff_switch_to(prev);                                \
        lose_fpu_inatomic(1, prev);                                     \
+       if (tsk_used_math(next))                                        \
+               __sanitize_fcr31(next);                                 \
        if (cpu_has_dsp) {                                              \
                __save_dsp(prev);                                       \
                __restore_dsp(next);                                    \
index 4a2349302b552c5a7c4772c235553b4bdbef4695..dd179fd8acdac4a6e9f47257f79263f4a6432c46 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __ASM_TLB_H
 #define __ASM_TLB_H
 
+#include <asm/cpu-features.h>
+#include <asm/mipsregs.h>
+
 /*
  * MIPS doesn't need any special per-pte or per-vma handling, except
  * we need to flush cache for area to be unmapped.
                ((CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) |               \
                 (cpu_has_tlbinv ? MIPS_ENTRYHI_EHINV : 0))
 
+static inline unsigned int num_wired_entries(void)
+{
+       unsigned int wired = read_c0_wired();
+
+       if (cpu_has_mips_r6)
+               wired &= MIPSR6_WIRED_WIRED;
+
+       return wired;
+}
+
 #include <asm-generic/tlb.h>
 
 #endif /* __ASM_TLB_H */
index 2a45867d3b4f5ff89636d561379592e8ebabae05..a4964c334cab66eba2e41e34c25db281a1729555 100644 (file)
@@ -21,6 +21,11 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock);
 
 static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags);
 
+phys_addr_t __weak mips_cpc_default_phys_base(void)
+{
+       return 0;
+}
+
 /**
  * mips_cpc_phys_base - retrieve the physical base address of the CPC
  *
@@ -43,8 +48,12 @@ static phys_addr_t mips_cpc_phys_base(void)
        if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK)
                return cpc_base & CM_GCR_CPC_BASE_CPCBASE_MSK;
 
-       /* Otherwise, give it the default address & enable it */
+       /* Otherwise, use the default address */
        cpc_base = mips_cpc_default_phys_base();
+       if (!cpc_base)
+               return cpc_base;
+
+       /* Enable the CPC, mapped at the default address */
        write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN_MSK);
        return cpc_base;
 }
index 22dedd62818ad08d517de10a705da5cf2b9a5279..bd09853aecdfa1e567717cc35a9d19e786468391 100644 (file)
@@ -899,7 +899,7 @@ static inline int mipsr2_find_op_func(struct pt_regs *regs, u32 inst,
  * mipsr2_decoder: Decode and emulate a MIPS R2 instruction
  * @regs: Process register set
  * @inst: Instruction to decode and emulate
- * @fcr31: Floating Point Control and Status Register returned
+ * @fcr31: Floating Point Control and Status Register Cause bits returned
  */
 int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
 {
@@ -1172,13 +1172,13 @@ fpu_emul:
 
                err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
                                               &fault_addr);
-               *fcr31 = current->thread.fpu.fcr31;
 
                /*
-                * We can't allow the emulated instruction to leave any of
-                * the cause bits set in $fcr31.
+                * We can't allow the emulated instruction to leave any
+                * enabled Cause bits set in $fcr31.
                 */
-               current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+               *fcr31 = res = mask_fcr31_x(current->thread.fpu.fcr31);
+               current->thread.fpu.fcr31 &= ~res;
 
                /*
                 * this is a tricky issue - lose_fpu() uses LL/SC atomics
index 6103b24d1bfcb781ae436ceb2a7c94ec7801df34..a92994d60e91e4b768ac6570012ad64c1c86885d 100644 (file)
@@ -79,16 +79,15 @@ void ptrace_disable(struct task_struct *child)
 }
 
 /*
- * Poke at FCSR according to its mask.  Don't set the cause bits as
- * this is currently not handled correctly in FP context restoration
- * and will cause an oops if a corresponding enable bit is set.
+ * Poke at FCSR according to its mask.  Set the Cause bits even
+ * if a corresponding Enable bit is set.  This will be noticed at
+ * the time the thread is switched to and SIGFPE thrown accordingly.
  */
 static void ptrace_setfcr31(struct task_struct *child, u32 value)
 {
        u32 fcr31;
        u32 mask;
 
-       value &= ~FPU_CSR_ALL_X;
        fcr31 = child->thread.fpu.fcr31;
        mask = boot_cpu_data.fpu_msk31;
        child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
@@ -817,6 +816,7 @@ long arch_ptrace(struct task_struct *child, long request,
                        break;
 #endif
                case FPC_CSR:
+                       init_fp_ctx(child);
                        ptrace_setfcr31(child, data);
                        break;
                case DSP_BASE ... DSP_BASE + 5: {
index 283b5a1967d1461298bf065b2073d62c6296dc1d..7e71a4e0281ba9cc3c2190dd9a06d958754155fb 100644 (file)
@@ -70,7 +70,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        break;
 
                copied = access_process_vm(child, (u64)addrOthers, &tmp,
-                               sizeof(tmp), 0);
+                               sizeof(tmp), FOLL_FORCE);
                if (copied != sizeof(tmp))
                        break;
                ret = put_user(tmp, (u32 __user *) (unsigned long) data);
@@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        break;
                ret = 0;
                if (access_process_vm(child, (u64)addrOthers, &data,
-                                       sizeof(data), 1) == sizeof(data))
+                                       sizeof(data),
+                                       FOLL_FORCE | FOLL_WRITE) == sizeof(data))
                        break;
                ret = -EIO;
                break;
index b4ac6374a38f28e182b2558934ff979b88b33bb2..918f2f6d3861a87dccc85f5256bf9b89cc1d56d3 100644 (file)
 #include <asm/regdef.h>
 
 #define EX(a,b)                                                        \
+9:     a,##b;                                                  \
+       .section __ex_table,"a";                                \
+       PTR     9b,fault;                                       \
+       .previous
+
+#define EX2(a,b)                                               \
 9:     a,##b;                                                  \
        .section __ex_table,"a";                                \
        PTR     9b,bad_stack;                                   \
+       PTR     9b+4,bad_stack;                                 \
        .previous
 
        .set    noreorder
        .set    mips1
-       /* Save floating point context */
+
+/**
+ * _save_fp_context() - save FP context from the FPU
+ * @a0 - pointer to fpregs field of sigcontext
+ * @a1 - pointer to fpc_csr field of sigcontext
+ *
+ * Save FP context, including the 32 FP data registers and the FP
+ * control & status register, from the FPU to signal context.
+ */
 LEAF(_save_fp_context)
        .set    push
        SET_HARDFLOAT
        li      v0, 0                                   # assume success
-       cfc1    t1,fcr31
-       EX(swc1 $f0,(SC_FPREGS+0)(a0))
-       EX(swc1 $f1,(SC_FPREGS+8)(a0))
-       EX(swc1 $f2,(SC_FPREGS+16)(a0))
-       EX(swc1 $f3,(SC_FPREGS+24)(a0))
-       EX(swc1 $f4,(SC_FPREGS+32)(a0))
-       EX(swc1 $f5,(SC_FPREGS+40)(a0))
-       EX(swc1 $f6,(SC_FPREGS+48)(a0))
-       EX(swc1 $f7,(SC_FPREGS+56)(a0))
-       EX(swc1 $f8,(SC_FPREGS+64)(a0))
-       EX(swc1 $f9,(SC_FPREGS+72)(a0))
-       EX(swc1 $f10,(SC_FPREGS+80)(a0))
-       EX(swc1 $f11,(SC_FPREGS+88)(a0))
-       EX(swc1 $f12,(SC_FPREGS+96)(a0))
-       EX(swc1 $f13,(SC_FPREGS+104)(a0))
-       EX(swc1 $f14,(SC_FPREGS+112)(a0))
-       EX(swc1 $f15,(SC_FPREGS+120)(a0))
-       EX(swc1 $f16,(SC_FPREGS+128)(a0))
-       EX(swc1 $f17,(SC_FPREGS+136)(a0))
-       EX(swc1 $f18,(SC_FPREGS+144)(a0))
-       EX(swc1 $f19,(SC_FPREGS+152)(a0))
-       EX(swc1 $f20,(SC_FPREGS+160)(a0))
-       EX(swc1 $f21,(SC_FPREGS+168)(a0))
-       EX(swc1 $f22,(SC_FPREGS+176)(a0))
-       EX(swc1 $f23,(SC_FPREGS+184)(a0))
-       EX(swc1 $f24,(SC_FPREGS+192)(a0))
-       EX(swc1 $f25,(SC_FPREGS+200)(a0))
-       EX(swc1 $f26,(SC_FPREGS+208)(a0))
-       EX(swc1 $f27,(SC_FPREGS+216)(a0))
-       EX(swc1 $f28,(SC_FPREGS+224)(a0))
-       EX(swc1 $f29,(SC_FPREGS+232)(a0))
-       EX(swc1 $f30,(SC_FPREGS+240)(a0))
-       EX(swc1 $f31,(SC_FPREGS+248)(a0))
-       EX(sw   t1,(SC_FPC_CSR)(a0))
-       cfc1    t0,$0                           # implementation/version
+       cfc1    t1, fcr31
+       EX2(s.d $f0, 0(a0))
+       EX2(s.d $f2, 16(a0))
+       EX2(s.d $f4, 32(a0))
+       EX2(s.d $f6, 48(a0))
+       EX2(s.d $f8, 64(a0))
+       EX2(s.d $f10, 80(a0))
+       EX2(s.d $f12, 96(a0))
+       EX2(s.d $f14, 112(a0))
+       EX2(s.d $f16, 128(a0))
+       EX2(s.d $f18, 144(a0))
+       EX2(s.d $f20, 160(a0))
+       EX2(s.d $f22, 176(a0))
+       EX2(s.d $f24, 192(a0))
+       EX2(s.d $f26, 208(a0))
+       EX2(s.d $f28, 224(a0))
+       EX2(s.d $f30, 240(a0))
        jr      ra
+        EX(sw  t1, (a1))
        .set    pop
-       .set    nomacro
-        EX(sw  t0,(SC_FPC_EIR)(a0))
-       .set    macro
        END(_save_fp_context)
 
-/*
- * Restore FPU state:
- *  - fp gp registers
- *  - cp1 status/control register
+/**
+ * _restore_fp_context() - restore FP context to the FPU
+ * @a0 - pointer to fpregs field of sigcontext
+ * @a1 - pointer to fpc_csr field of sigcontext
  *
- * We base the decision which registers to restore from the signal stack
- * frame on the current content of c0_status, not on the content of the
- * stack frame which might have been changed by the user.
+ * Restore FP context, including the 32 FP data registers and the FP
+ * control & status register, from signal context to the FPU.
  */
 LEAF(_restore_fp_context)
        .set    push
        SET_HARDFLOAT
        li      v0, 0                                   # assume success
-       EX(lw t0,(SC_FPC_CSR)(a0))
-       EX(lwc1 $f0,(SC_FPREGS+0)(a0))
-       EX(lwc1 $f1,(SC_FPREGS+8)(a0))
-       EX(lwc1 $f2,(SC_FPREGS+16)(a0))
-       EX(lwc1 $f3,(SC_FPREGS+24)(a0))
-       EX(lwc1 $f4,(SC_FPREGS+32)(a0))
-       EX(lwc1 $f5,(SC_FPREGS+40)(a0))
-       EX(lwc1 $f6,(SC_FPREGS+48)(a0))
-       EX(lwc1 $f7,(SC_FPREGS+56)(a0))
-       EX(lwc1 $f8,(SC_FPREGS+64)(a0))
-       EX(lwc1 $f9,(SC_FPREGS+72)(a0))
-       EX(lwc1 $f10,(SC_FPREGS+80)(a0))
-       EX(lwc1 $f11,(SC_FPREGS+88)(a0))
-       EX(lwc1 $f12,(SC_FPREGS+96)(a0))
-       EX(lwc1 $f13,(SC_FPREGS+104)(a0))
-       EX(lwc1 $f14,(SC_FPREGS+112)(a0))
-       EX(lwc1 $f15,(SC_FPREGS+120)(a0))
-       EX(lwc1 $f16,(SC_FPREGS+128)(a0))
-       EX(lwc1 $f17,(SC_FPREGS+136)(a0))
-       EX(lwc1 $f18,(SC_FPREGS+144)(a0))
-       EX(lwc1 $f19,(SC_FPREGS+152)(a0))
-       EX(lwc1 $f20,(SC_FPREGS+160)(a0))
-       EX(lwc1 $f21,(SC_FPREGS+168)(a0))
-       EX(lwc1 $f22,(SC_FPREGS+176)(a0))
-       EX(lwc1 $f23,(SC_FPREGS+184)(a0))
-       EX(lwc1 $f24,(SC_FPREGS+192)(a0))
-       EX(lwc1 $f25,(SC_FPREGS+200)(a0))
-       EX(lwc1 $f26,(SC_FPREGS+208)(a0))
-       EX(lwc1 $f27,(SC_FPREGS+216)(a0))
-       EX(lwc1 $f28,(SC_FPREGS+224)(a0))
-       EX(lwc1 $f29,(SC_FPREGS+232)(a0))
-       EX(lwc1 $f30,(SC_FPREGS+240)(a0))
-       EX(lwc1 $f31,(SC_FPREGS+248)(a0))
+       EX(lw t0, (a1))
+       EX2(l.d $f0, 0(a0))
+       EX2(l.d $f2, 16(a0))
+       EX2(l.d $f4, 32(a0))
+       EX2(l.d $f6, 48(a0))
+       EX2(l.d $f8, 64(a0))
+       EX2(l.d $f10, 80(a0))
+       EX2(l.d $f12, 96(a0))
+       EX2(l.d $f14, 112(a0))
+       EX2(l.d $f16, 128(a0))
+       EX2(l.d $f18, 144(a0))
+       EX2(l.d $f20, 160(a0))
+       EX2(l.d $f22, 176(a0))
+       EX2(l.d $f24, 192(a0))
+       EX2(l.d $f26, 208(a0))
+       EX2(l.d $f28, 224(a0))
+       EX2(l.d $f30, 240(a0))
        jr      ra
-        ctc1   t0,fcr31
+        ctc1   t0, fcr31
        .set    pop
        END(_restore_fp_context)
        .set    reorder
index 47077380c15c43aca685a3aacbea837f8cc42a65..9cc7bfab3419a80e02ae344b6bd154e154370864 100644 (file)
        .set    push
        SET_HARDFLOAT
 
-       /* Save floating point context */
+/**
+ * _save_fp_context() - save FP context from the FPU
+ * @a0 - pointer to fpregs field of sigcontext
+ * @a1 - pointer to fpc_csr field of sigcontext
+ *
+ * Save FP context, including the 32 FP data registers and the FP
+ * control & status register, from the FPU to signal context.
+ */
        LEAF(_save_fp_context)
        mfc0    t0,CP0_STATUS
        sll     t0,t0,2
 
        cfc1    t1,fcr31
        /* Store the 16 double precision registers */
-       sdc1    $f0,(SC_FPREGS+0)(a0)
-       sdc1    $f2,(SC_FPREGS+16)(a0)
-       sdc1    $f4,(SC_FPREGS+32)(a0)
-       sdc1    $f6,(SC_FPREGS+48)(a0)
-       sdc1    $f8,(SC_FPREGS+64)(a0)
-       sdc1    $f10,(SC_FPREGS+80)(a0)
-       sdc1    $f12,(SC_FPREGS+96)(a0)
-       sdc1    $f14,(SC_FPREGS+112)(a0)
-       sdc1    $f16,(SC_FPREGS+128)(a0)
-       sdc1    $f18,(SC_FPREGS+144)(a0)
-       sdc1    $f20,(SC_FPREGS+160)(a0)
-       sdc1    $f22,(SC_FPREGS+176)(a0)
-       sdc1    $f24,(SC_FPREGS+192)(a0)
-       sdc1    $f26,(SC_FPREGS+208)(a0)
-       sdc1    $f28,(SC_FPREGS+224)(a0)
-       sdc1    $f30,(SC_FPREGS+240)(a0)
+       sdc1    $f0,0(a0)
+       sdc1    $f2,16(a0)
+       sdc1    $f4,32(a0)
+       sdc1    $f6,48(a0)
+       sdc1    $f8,64(a0)
+       sdc1    $f10,80(a0)
+       sdc1    $f12,96(a0)
+       sdc1    $f14,112(a0)
+       sdc1    $f16,128(a0)
+       sdc1    $f18,144(a0)
+       sdc1    $f20,160(a0)
+       sdc1    $f22,176(a0)
+       sdc1    $f24,192(a0)
+       sdc1    $f26,208(a0)
+       sdc1    $f28,224(a0)
+       sdc1    $f30,240(a0)
        jr      ra
-        sw     t0,SC_FPC_CSR(a0)
+        sw     t0,(a1)
 1:     jr      ra
         nop
        END(_save_fp_context)
 
-/* Restore FPU state:
- *  - fp gp registers
- *  - cp1 status/control register
+/**
+ * _restore_fp_context() - restore FP context to the FPU
+ * @a0 - pointer to fpregs field of sigcontext
+ * @a1 - pointer to fpc_csr field of sigcontext
  *
- * We base the decision which registers to restore from the signal stack
- * frame on the current content of c0_status, not on the content of the
- * stack frame which might have been changed by the user.
+ * Restore FP context, including the 32 FP data registers and the FP
+ * control & status register, from signal context to the FPU.
  */
        LEAF(_restore_fp_context)
        mfc0    t0,CP0_STATUS
        sll     t0,t0,2
 
        bgez    t0,1f
-        lw     t0,SC_FPC_CSR(a0)
+        lw     t0,(a1)
        /* Restore the 16 double precision registers */
-       ldc1    $f0,(SC_FPREGS+0)(a0)
-       ldc1    $f2,(SC_FPREGS+16)(a0)
-       ldc1    $f4,(SC_FPREGS+32)(a0)
-       ldc1    $f6,(SC_FPREGS+48)(a0)
-       ldc1    $f8,(SC_FPREGS+64)(a0)
-       ldc1    $f10,(SC_FPREGS+80)(a0)
-       ldc1    $f12,(SC_FPREGS+96)(a0)
-       ldc1    $f14,(SC_FPREGS+112)(a0)
-       ldc1    $f16,(SC_FPREGS+128)(a0)
-       ldc1    $f18,(SC_FPREGS+144)(a0)
-       ldc1    $f20,(SC_FPREGS+160)(a0)
-       ldc1    $f22,(SC_FPREGS+176)(a0)
-       ldc1    $f24,(SC_FPREGS+192)(a0)
-       ldc1    $f26,(SC_FPREGS+208)(a0)
-       ldc1    $f28,(SC_FPREGS+224)(a0)
-       ldc1    $f30,(SC_FPREGS+240)(a0)
+       ldc1    $f0,0(a0)
+       ldc1    $f2,16(a0)
+       ldc1    $f4,32(a0)
+       ldc1    $f6,48(a0)
+       ldc1    $f8,64(a0)
+       ldc1    $f10,80(a0)
+       ldc1    $f12,96(a0)
+       ldc1    $f14,112(a0)
+       ldc1    $f16,128(a0)
+       ldc1    $f18,144(a0)
+       ldc1    $f20,160(a0)
+       ldc1    $f22,176(a0)
+       ldc1    $f24,192(a0)
+       ldc1    $f26,208(a0)
+       ldc1    $f28,224(a0)
+       ldc1    $f30,240(a0)
        jr      ra
         ctc1   t0,fcr31
 1:     jr      ra
index ca1cc30c0891f7a94a6cb0f0e9bf4941fc817fd2..1958910b75c07aa18926df5d50f93987dbe58406 100644 (file)
@@ -200,7 +200,7 @@ static inline __init unsigned long get_random_boot(void)
 
 #if defined(CONFIG_USE_OF)
        /* Get any additional entropy passed in device tree */
-       {
+       if (initial_boot_params) {
                int node, len;
                u64 *prop;
 
index 0d57909d90261d69790156614394bce5325c5bc0..f66e5ce505b23db0e666adb727653df71104c5d1 100644 (file)
@@ -368,6 +368,19 @@ static void __init bootmem_init(void)
                end = PFN_DOWN(boot_mem_map.map[i].addr
                                + boot_mem_map.map[i].size);
 
+#ifndef CONFIG_HIGHMEM
+               /*
+                * Skip highmem here so we get an accurate max_low_pfn if low
+                * memory stops short of high memory.
+                * If the region overlaps HIGHMEM_START, end is clipped so
+                * max_pfn excludes the highmem portion.
+                */
+               if (start >= PFN_DOWN(HIGHMEM_START))
+                       continue;
+               if (end > PFN_DOWN(HIGHMEM_START))
+                       end = PFN_DOWN(HIGHMEM_START);
+#endif
+
                if (end > max_low_pfn)
                        max_low_pfn = end;
                if (start < min_low_pfn)
index 8d0170969e22274efec90f328b626aec51ddb00a..a7f81261c781f0d935fbf70feffdeca3d898703a 100644 (file)
@@ -36,7 +36,7 @@ EXPORT_SYMBOL(rtc_lock);
 
 int __weak rtc_mips_set_time(unsigned long sec)
 {
-       return 0;
+       return -ENODEV;
 }
 
 int __weak rtc_mips_set_mmss(unsigned long nowtime)
index 1f5fdee1dfc31a1be2335bebe79de934c0e2d065..3905003dfe2b918faa7acd39f350710c9ed6edd0 100644 (file)
@@ -156,7 +156,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
                print_ip_sym(pc);
                pc = unwind_stack(task, &sp, pc, &ra);
        } while (pc);
-       printk("\n");
+       pr_cont("\n");
 }
 
 /*
@@ -174,22 +174,24 @@ static void show_stacktrace(struct task_struct *task,
        printk("Stack :");
        i = 0;
        while ((unsigned long) sp & (PAGE_SIZE - 1)) {
-               if (i && ((i % (64 / field)) == 0))
-                       printk("\n       ");
+               if (i && ((i % (64 / field)) == 0)) {
+                       pr_cont("\n");
+                       printk("       ");
+               }
                if (i > 39) {
-                       printk(" ...");
+                       pr_cont(" ...");
                        break;
                }
 
                if (__get_user(stackdata, sp++)) {
-                       printk(" (Bad stack address)");
+                       pr_cont(" (Bad stack address)");
                        break;
                }
 
-               printk(" %0*lx", field, stackdata);
+               pr_cont(" %0*lx", field, stackdata);
                i++;
        }
-       printk("\n");
+       pr_cont("\n");
        show_backtrace(task, regs);
 }
 
@@ -229,18 +231,19 @@ static void show_code(unsigned int __user *pc)
        long i;
        unsigned short __user *pc16 = NULL;
 
-       printk("\nCode:");
+       printk("Code:");
 
        if ((unsigned long)pc & 1)
                pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
        for(i = -3 ; i < 6 ; i++) {
                unsigned int insn;
                if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) {
-                       printk(" (Bad address in epc)\n");
+                       pr_cont(" (Bad address in epc)\n");
                        break;
                }
-               printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
+               pr_cont("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
        }
+       pr_cont("\n");
 }
 
 static void __show_regs(const struct pt_regs *regs)
@@ -259,15 +262,15 @@ static void __show_regs(const struct pt_regs *regs)
                if ((i % 4) == 0)
                        printk("$%2d   :", i);
                if (i == 0)
-                       printk(" %0*lx", field, 0UL);
+                       pr_cont(" %0*lx", field, 0UL);
                else if (i == 26 || i == 27)
-                       printk(" %*s", field, "");
+                       pr_cont(" %*s", field, "");
                else
-                       printk(" %0*lx", field, regs->regs[i]);
+                       pr_cont(" %0*lx", field, regs->regs[i]);
 
                i++;
                if ((i % 4) == 0)
-                       printk("\n");
+                       pr_cont("\n");
        }
 
 #ifdef CONFIG_CPU_HAS_SMARTMIPS
@@ -288,46 +291,46 @@ static void __show_regs(const struct pt_regs *regs)
 
        if (cpu_has_3kex) {
                if (regs->cp0_status & ST0_KUO)
-                       printk("KUo ");
+                       pr_cont("KUo ");
                if (regs->cp0_status & ST0_IEO)
-                       printk("IEo ");
+                       pr_cont("IEo ");
                if (regs->cp0_status & ST0_KUP)
-                       printk("KUp ");
+                       pr_cont("KUp ");
                if (regs->cp0_status & ST0_IEP)
-                       printk("IEp ");
+                       pr_cont("IEp ");
                if (regs->cp0_status & ST0_KUC)
-                       printk("KUc ");
+                       pr_cont("KUc ");
                if (regs->cp0_status & ST0_IEC)
-                       printk("IEc ");
+                       pr_cont("IEc ");
        } else if (cpu_has_4kex) {
                if (regs->cp0_status & ST0_KX)
-                       printk("KX ");
+                       pr_cont("KX ");
                if (regs->cp0_status & ST0_SX)
-                       printk("SX ");
+                       pr_cont("SX ");
                if (regs->cp0_status & ST0_UX)
-                       printk("UX ");
+                       pr_cont("UX ");
                switch (regs->cp0_status & ST0_KSU) {
                case KSU_USER:
-                       printk("USER ");
+                       pr_cont("USER ");
                        break;
                case KSU_SUPERVISOR:
-                       printk("SUPERVISOR ");
+                       pr_cont("SUPERVISOR ");
                        break;
                case KSU_KERNEL:
-                       printk("KERNEL ");
+                       pr_cont("KERNEL ");
                        break;
                default:
-                       printk("BAD_MODE ");
+                       pr_cont("BAD_MODE ");
                        break;
                }
                if (regs->cp0_status & ST0_ERL)
-                       printk("ERL ");
+                       pr_cont("ERL ");
                if (regs->cp0_status & ST0_EXL)
-                       printk("EXL ");
+                       pr_cont("EXL ");
                if (regs->cp0_status & ST0_IE)
-                       printk("IE ");
+                       pr_cont("IE ");
        }
-       printk("\n");
+       pr_cont("\n");
 
        exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
        printk("Cause : %08x (ExcCode %02x)\n", cause, exccode);
@@ -705,6 +708,32 @@ asmlinkage void do_ov(struct pt_regs *regs)
        exception_exit(prev_state);
 }
 
+/*
+ * Send SIGFPE according to FCSR Cause bits, which must have already
+ * been masked against Enable bits.  This is impotant as Inexact can
+ * happen together with Overflow or Underflow, and `ptrace' can set
+ * any bits.
+ */
+void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
+                    struct task_struct *tsk)
+{
+       struct siginfo si = { .si_addr = fault_addr, .si_signo = SIGFPE };
+
+       if (fcr31 & FPU_CSR_INV_X)
+               si.si_code = FPE_FLTINV;
+       else if (fcr31 & FPU_CSR_DIV_X)
+               si.si_code = FPE_FLTDIV;
+       else if (fcr31 & FPU_CSR_OVF_X)
+               si.si_code = FPE_FLTOVF;
+       else if (fcr31 & FPU_CSR_UDF_X)
+               si.si_code = FPE_FLTUND;
+       else if (fcr31 & FPU_CSR_INE_X)
+               si.si_code = FPE_FLTRES;
+       else
+               si.si_code = __SI_FAULT;
+       force_sig_info(SIGFPE, &si, tsk);
+}
+
 int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
 {
        struct siginfo si = { 0 };
@@ -715,27 +744,7 @@ int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
                return 0;
 
        case SIGFPE:
-               si.si_addr = fault_addr;
-               si.si_signo = sig;
-               /*
-                * Inexact can happen together with Overflow or Underflow.
-                * Respect the mask to deliver the correct exception.
-                */
-               fcr31 &= (fcr31 & FPU_CSR_ALL_E) <<
-                        (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E));
-               if (fcr31 & FPU_CSR_INV_X)
-                       si.si_code = FPE_FLTINV;
-               else if (fcr31 & FPU_CSR_DIV_X)
-                       si.si_code = FPE_FLTDIV;
-               else if (fcr31 & FPU_CSR_OVF_X)
-                       si.si_code = FPE_FLTOVF;
-               else if (fcr31 & FPU_CSR_UDF_X)
-                       si.si_code = FPE_FLTUND;
-               else if (fcr31 & FPU_CSR_INE_X)
-                       si.si_code = FPE_FLTRES;
-               else
-                       si.si_code = __SI_FAULT;
-               force_sig_info(sig, &si, current);
+               force_fcr31_sig(fcr31, fault_addr, current);
                return 1;
 
        case SIGBUS:
@@ -799,13 +808,13 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
        /* Run the emulator */
        sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
                                       &fault_addr);
-       fcr31 = current->thread.fpu.fcr31;
 
        /*
-        * We can't allow the emulated instruction to leave any of
-        * the cause bits set in $fcr31.
+        * We can't allow the emulated instruction to leave any
+        * enabled Cause bits set in $fcr31.
         */
-       current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+       fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+       current->thread.fpu.fcr31 &= ~fcr31;
 
        /* Restore the hardware register state */
        own_fpu(1);
@@ -831,7 +840,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                goto out;
 
        /* Clear FCSR.Cause before enabling interrupts */
-       write_32bit_cp1_register(CP1_STATUS, fcr31 & ~FPU_CSR_ALL_X);
+       write_32bit_cp1_register(CP1_STATUS, fcr31 & ~mask_fcr31_x(fcr31));
        local_irq_enable();
 
        die_if_kernel("FP exception in kernel code", regs);
@@ -853,13 +862,13 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                /* Run the emulator */
                sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
                                               &fault_addr);
-               fcr31 = current->thread.fpu.fcr31;
 
                /*
-                * We can't allow the emulated instruction to leave any of
-                * the cause bits set in $fcr31.
+                * We can't allow the emulated instruction to leave any
+                * enabled Cause bits set in $fcr31.
                 */
-               current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+               fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+               current->thread.fpu.fcr31 &= ~fcr31;
 
                /* Restore the hardware register state */
                own_fpu(1);     /* Using the FPU again.  */
@@ -1424,13 +1433,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 
                sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
                                               &fault_addr);
-               fcr31 = current->thread.fpu.fcr31;
 
                /*
                 * We can't allow the emulated instruction to leave
-                * any of the cause bits set in $fcr31.
+                * any enabled Cause bits set in $fcr31.
                 */
-               current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+               fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+               current->thread.fpu.fcr31 &= ~fcr31;
 
                /* Send a signal if required.  */
                if (!process_fpemu_return(sig, fault_addr, fcr31) && !err)
index 8770f32c9e0bed601898dcbe3ac6504adaee8953..aa0937423e287b06e007b2251977ff10e23c63b2 100644 (file)
@@ -790,15 +790,15 @@ enum emulation_result kvm_mips_emul_eret(struct kvm_vcpu *vcpu)
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        enum emulation_result er = EMULATE_DONE;
 
-       if (kvm_read_c0_guest_status(cop0) & ST0_EXL) {
+       if (kvm_read_c0_guest_status(cop0) & ST0_ERL) {
+               kvm_clear_c0_guest_status(cop0, ST0_ERL);
+               vcpu->arch.pc = kvm_read_c0_guest_errorepc(cop0);
+       } else if (kvm_read_c0_guest_status(cop0) & ST0_EXL) {
                kvm_debug("[%#lx] ERET to %#lx\n", vcpu->arch.pc,
                          kvm_read_c0_guest_epc(cop0));
                kvm_clear_c0_guest_status(cop0, ST0_EXL);
                vcpu->arch.pc = kvm_read_c0_guest_epc(cop0);
 
-       } else if (kvm_read_c0_guest_status(cop0) & ST0_ERL) {
-               kvm_clear_c0_guest_status(cop0, ST0_ERL);
-               vcpu->arch.pc = kvm_read_c0_guest_errorepc(cop0);
        } else {
                kvm_err("[%#lx] ERET when MIPS_SR_EXL|MIPS_SR_ERL == 0\n",
                        vcpu->arch.pc);
@@ -1528,13 +1528,25 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
                                            struct kvm_vcpu *vcpu)
 {
        enum emulation_result er = EMULATE_DO_MMIO;
+       unsigned long curr_pc;
        u32 op, rt;
        u32 bytes;
 
        rt = inst.i_format.rt;
        op = inst.i_format.opcode;
 
-       vcpu->arch.pending_load_cause = cause;
+       /*
+        * Find the resume PC now while we have safe and easy access to the
+        * prior branch instruction, and save it for
+        * kvm_mips_complete_mmio_load() to restore later.
+        */
+       curr_pc = vcpu->arch.pc;
+       er = update_pc(vcpu, cause);
+       if (er == EMULATE_FAIL)
+               return er;
+       vcpu->arch.io_pc = vcpu->arch.pc;
+       vcpu->arch.pc = curr_pc;
+
        vcpu->arch.io_gpr = rt;
 
        switch (op) {
@@ -2494,9 +2506,8 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
                goto done;
        }
 
-       er = update_pc(vcpu, vcpu->arch.pending_load_cause);
-       if (er == EMULATE_FAIL)
-               return er;
+       /* Restore saved resume PC */
+       vcpu->arch.pc = vcpu->arch.io_pc;
 
        switch (run->mmio.len) {
        case 4:
@@ -2518,11 +2529,6 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
                break;
        }
 
-       if (vcpu->arch.pending_load_cause & CAUSEF_BD)
-               kvm_debug("[%#lx] Completing %d byte BD Load to gpr %d (0x%08lx) type %d\n",
-                         vcpu->arch.pc, run->mmio.len, vcpu->arch.io_gpr, *gpr,
-                         vcpu->mmio_needed);
-
 done:
        return er;
 }
index ce961495b5e123f374a4d129387daffa20974373..06a60b19acfb53c2788ba6b9c79de983bb6fe43e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/err.h>
 #include <linux/kdebug.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/bootmem.h>
@@ -425,7 +426,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 static void kvm_mips_check_asids(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
-       int cpu = smp_processor_id();
+       int i, cpu = smp_processor_id();
        unsigned int gasid;
 
        /*
@@ -441,6 +442,9 @@ static void kvm_mips_check_asids(struct kvm_vcpu *vcpu)
                                                vcpu);
                        vcpu->arch.guest_user_asid[cpu] =
                                vcpu->arch.guest_user_mm.context.asid[cpu];
+                       for_each_possible_cpu(i)
+                               if (i != cpu)
+                                       vcpu->arch.guest_user_asid[cpu] = 0;
                        vcpu->arch.last_user_gasid = gasid;
                }
        }
index 03883ba806e252d451f5df348c5414b3b31971cb..3b677c851be0794861d06a2d7b875b7fddfedff7 100644 (file)
@@ -260,13 +260,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
        if ((vcpu->arch.guest_user_asid[cpu] ^ asid_cache(cpu)) &
                                                asid_version_mask(cpu)) {
-               u32 gasid = kvm_read_c0_guest_entryhi(vcpu->arch.cop0) &
-                               KVM_ENTRYHI_ASID;
-
                kvm_get_new_mmu_context(&vcpu->arch.guest_user_mm, cpu, vcpu);
                vcpu->arch.guest_user_asid[cpu] =
                    vcpu->arch.guest_user_mm.context.asid[cpu];
-               vcpu->arch.last_user_gasid = gasid;
                newasid++;
 
                kvm_debug("[%d]: cpu_context: %#lx\n", cpu,
index 2a1b3021589cf111aa26f57f0e8250534fd13f9a..82bbd0e2e298fa504f3f1995cf83aee8b7746569 100644 (file)
@@ -24,7 +24,7 @@
 
 /* GPE frequency selection */
 #define GPPC_OFFSET            24
-#define GPEFREQ_MASK           0x00000C0
+#define GPEFREQ_MASK           0x0000C00
 #define GPEFREQ_OFFSET         10
 /* Clock status register */
 #define SYSCTL_CLKS            0x0000
index 0f80b936e75ec92015d1ebdfb815dfaed14a9909..6eb50a7137db05c9dc18b38bf33b317192aa058a 100644 (file)
@@ -135,42 +135,42 @@ static void dump_tlb(int first, int last)
                c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
                c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
 
-               printk("va=%0*lx asid=%0*lx",
-                      vwidth, (entryhi & ~0x1fffUL),
-                      asidwidth, entryhi & asidmask);
+               pr_cont("va=%0*lx asid=%0*lx",
+                       vwidth, (entryhi & ~0x1fffUL),
+                       asidwidth, entryhi & asidmask);
                if (cpu_has_guestid)
-                       printk(" gid=%02lx",
-                              (guestctl1 & MIPS_GCTL1_RID)
+                       pr_cont(" gid=%02lx",
+                               (guestctl1 & MIPS_GCTL1_RID)
                                        >> MIPS_GCTL1_RID_SHIFT);
                /* RI/XI are in awkward places, so mask them off separately */
                pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
                if (xpa)
                        pa |= (unsigned long long)readx_c0_entrylo0() << 30;
                pa = (pa << 6) & PAGE_MASK;
-               printk("\n\t[");
+               pr_cont("\n\t[");
                if (cpu_has_rixi)
-                       printk("ri=%d xi=%d ",
-                              (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
-                              (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
-               printk("pa=%0*llx c=%d d=%d v=%d g=%d] [",
-                      pwidth, pa, c0,
-                      (entrylo0 & ENTRYLO_D) ? 1 : 0,
-                      (entrylo0 & ENTRYLO_V) ? 1 : 0,
-                      (entrylo0 & ENTRYLO_G) ? 1 : 0);
+                       pr_cont("ri=%d xi=%d ",
+                               (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
+                               (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
+               pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d] [",
+                       pwidth, pa, c0,
+                       (entrylo0 & ENTRYLO_D) ? 1 : 0,
+                       (entrylo0 & ENTRYLO_V) ? 1 : 0,
+                       (entrylo0 & ENTRYLO_G) ? 1 : 0);
                /* RI/XI are in awkward places, so mask them off separately */
                pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
                if (xpa)
                        pa |= (unsigned long long)readx_c0_entrylo1() << 30;
                pa = (pa << 6) & PAGE_MASK;
                if (cpu_has_rixi)
-                       printk("ri=%d xi=%d ",
-                              (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
-                              (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
-               printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
-                      pwidth, pa, c1,
-                      (entrylo1 & ENTRYLO_D) ? 1 : 0,
-                      (entrylo1 & ENTRYLO_V) ? 1 : 0,
-                      (entrylo1 & ENTRYLO_G) ? 1 : 0);
+                       pr_cont("ri=%d xi=%d ",
+                               (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
+                               (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
+               pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
+                       pwidth, pa, c1,
+                       (entrylo1 & ENTRYLO_D) ? 1 : 0,
+                       (entrylo1 & ENTRYLO_V) ? 1 : 0,
+                       (entrylo1 & ENTRYLO_G) ? 1 : 0);
        }
        printk("\n");
 
index 744f4a7bc49dfa5eabbde9b78228e0d2065799d4..85b4086e553e8734cf4b286a2a65d5159ed4f5d9 100644 (file)
@@ -53,15 +53,15 @@ static void dump_tlb(int first, int last)
                         */
                        printk("Index: %2d ", i);
 
-                       printk("va=%08lx asid=%08lx"
-                              "  [pa=%06lx n=%d d=%d v=%d g=%d]",
-                              entryhi & PAGE_MASK,
-                              entryhi & asid_mask,
-                              entrylo0 & PAGE_MASK,
-                              (entrylo0 & R3K_ENTRYLO_N) ? 1 : 0,
-                              (entrylo0 & R3K_ENTRYLO_D) ? 1 : 0,
-                              (entrylo0 & R3K_ENTRYLO_V) ? 1 : 0,
-                              (entrylo0 & R3K_ENTRYLO_G) ? 1 : 0);
+                       pr_cont("va=%08lx asid=%08lx"
+                               "  [pa=%06lx n=%d d=%d v=%d g=%d]",
+                               entryhi & PAGE_MASK,
+                               entryhi & asid_mask,
+                               entrylo0 & PAGE_MASK,
+                               (entrylo0 & R3K_ENTRYLO_N) ? 1 : 0,
+                               (entrylo0 & R3K_ENTRYLO_D) ? 1 : 0,
+                               (entrylo0 & R3K_ENTRYLO_V) ? 1 : 0,
+                               (entrylo0 & R3K_ENTRYLO_G) ? 1 : 0);
                }
        }
        printk("\n");
index d56a855828c2bbc1235873ab7fd03c3836fb7b4a..3bef306cdfdbb85917ef390ac1696897532124e1 100644 (file)
@@ -209,17 +209,18 @@ bad_area_nosemaphore:
                if (show_unhandled_signals &&
                    unhandled_signal(tsk, SIGSEGV) &&
                    __ratelimit(&ratelimit_state)) {
-                       pr_info("\ndo_page_fault(): sending SIGSEGV to %s for invalid %s %0*lx",
+                       pr_info("do_page_fault(): sending SIGSEGV to %s for invalid %s %0*lx\n",
                                tsk->comm,
                                write ? "write access to" : "read access from",
                                field, address);
                        pr_info("epc = %0*lx in", field,
                                (unsigned long) regs->cp0_epc);
-                       print_vma_addr(" ", regs->cp0_epc);
+                       print_vma_addr(KERN_CONT " ", regs->cp0_epc);
+                       pr_cont("\n");
                        pr_info("ra  = %0*lx in", field,
                                (unsigned long) regs->regs[31]);
-                       print_vma_addr(" ", regs->regs[31]);
-                       pr_info("\n");
+                       print_vma_addr(KERN_CONT " ", regs->regs[31]);
+                       pr_cont("\n");
                }
                current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
                info.si_signo = SIGSEGV;
index 42d124fb6474477c896e4618713e5b6d65d6e8f3..d8c3c159289a2953b8ae495a1da34d27d095b161 100644 (file)
@@ -287,7 +287,7 @@ slow_irqon:
        pages += nr;
 
        ret = get_user_pages_unlocked(start, (end - start) >> PAGE_SHIFT,
-                                     write, 0, pages);
+                                     pages, write ? FOLL_WRITE : 0);
 
        /* Have to be a bit careful with return values */
        if (nr > 0) {
index 3a6edecc3f385e4bd897750aa66488623f60411e..e86ebcf5c071f8c9d9737b9d1d1e21cd95204212 100644 (file)
@@ -118,7 +118,7 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
                writex_c0_entrylo1(entrylo);
        }
 #endif
-       tlbidx = read_c0_wired();
+       tlbidx = num_wired_entries();
        write_c0_wired(tlbidx + 1);
        write_c0_index(tlbidx);
        mtc0_tlbw_hazard();
@@ -147,7 +147,7 @@ void kunmap_coherent(void)
 
        local_irq_save(flags);
        old_ctx = read_c0_entryhi();
-       wired = read_c0_wired() - 1;
+       wired = num_wired_entries() - 1;
        write_c0_wired(wired);
        write_c0_index(wired);
        write_c0_entryhi(UNIQUE_ENTRYHI(wired));
index bba9c1484b41e1bc8c124b3a2c50e53eb27e032c..0596505770dba382d4821df12f67cd431480873a 100644 (file)
@@ -65,7 +65,7 @@ void local_flush_tlb_all(void)
        write_c0_entrylo0(0);
        write_c0_entrylo1(0);
 
-       entry = read_c0_wired();
+       entry = num_wired_entries();
 
        /*
         * Blast 'em all away.
@@ -385,7 +385,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
        old_ctx = read_c0_entryhi();
        htw_stop();
        old_pagemask = read_c0_pagemask();
-       wired = read_c0_wired();
+       wired = num_wired_entries();
        write_c0_wired(wired + 1);
        write_c0_index(wired);
        tlbw_use_hazard();      /* What is the hazard here? */
@@ -449,7 +449,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
        htw_stop();
        old_ctx = read_c0_entryhi();
        old_pagemask = read_c0_pagemask();
-       wired = read_c0_wired();
+       wired = num_wired_entries();
        if (--temp_tlb_entry < wired) {
                printk(KERN_WARNING
                       "No TLB space left for add_temporary_entry\n");
index d9563ddb337eab4e44d052ebd285206b09788f13..746bf5caaffc7989884813b16bc3fd3fce85d0ef 100644 (file)
@@ -324,6 +324,7 @@ static int __init nios2_time_init(struct device_node *timer)
                ret = nios2_clocksource_init(timer);
                break;
        default:
+               ret = 0;
                break;
        }
 
index 4ce7a01a252dc6a2c191917e2516a5ffe27aa1d1..5f55da9cbfd5ce8ff72d9baea51671bcedd44732 100644 (file)
@@ -23,6 +23,8 @@
  * they shouldn't be hard-coded!
  */
 
+#define __ro_after_init __read_mostly
+
 #define L1_CACHE_BYTES 16
 #define L1_CACHE_SHIFT 4
 
index 71c4a3aa3752cf485813b011cc4489ad14b0b1b5..a14b865870131a052c995fed98cc9e3ed7a3cd2d 100644 (file)
@@ -34,7 +34,9 @@ config PARISC
        select HAVE_ARCH_HASH
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
-       select HAVE_UNSTABLE_SCHED_CLOCK if (SMP || !64BIT)
+       select GENERIC_SCHED_CLOCK
+       select HAVE_UNSTABLE_SCHED_CLOCK if SMP
+       select GENERIC_CLOCKEVENTS
        select ARCH_NO_COHERENT_DMA_MMAP
        select CPU_NO_EFFICIENT_FFS
 
index c2c43f71468498828f924ebc54b9aa3f189ba95e..3a4ed9f91d5727a5293780967411328ae8cc6310 100644 (file)
@@ -65,9 +65,9 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
                unsigned long flags;                            \
                spin_lock_irqsave(&pa_tlb_lock, flags);         \
                old_pte = *ptep;                                \
-               set_pte(ptep, pteval);                          \
                if (pte_inserted(old_pte))                      \
                        purge_tlb_entries(mm, addr);            \
+               set_pte(ptep, pteval);                          \
                spin_unlock_irqrestore(&pa_tlb_lock, flags);    \
        } while (0)
 
@@ -478,8 +478,8 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
                spin_unlock_irqrestore(&pa_tlb_lock, flags);
                return 0;
        }
-       set_pte(ptep, pte_mkold(pte));
        purge_tlb_entries(vma->vm_mm, addr);
+       set_pte(ptep, pte_mkold(pte));
        spin_unlock_irqrestore(&pa_tlb_lock, flags);
        return 1;
 }
@@ -492,9 +492,9 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 
        spin_lock_irqsave(&pa_tlb_lock, flags);
        old_pte = *ptep;
-       set_pte(ptep, __pte(0));
        if (pte_inserted(old_pte))
                purge_tlb_entries(mm, addr);
+       set_pte(ptep, __pte(0));
        spin_unlock_irqrestore(&pa_tlb_lock, flags);
 
        return old_pte;
@@ -504,8 +504,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 {
        unsigned long flags;
        spin_lock_irqsave(&pa_tlb_lock, flags);
-       set_pte(ptep, pte_wrprotect(*ptep));
        purge_tlb_entries(mm, addr);
+       set_pte(ptep, pte_wrprotect(*ptep));
        spin_unlock_irqrestore(&pa_tlb_lock, flags);
 }
 
index a9b9407f38f7c63a3ad9f42b0dcd7d11d1fb8d92..6b0741e7a7ed3ee4060d619a8999b50dab12dac3 100644 (file)
 
 #define __IGNORE_select                /* newselect */
 #define __IGNORE_fadvise64     /* fadvise64_64 */
-
+#define __IGNORE_pkey_mprotect
+#define __IGNORE_pkey_alloc
+#define __IGNORE_pkey_free
 
 #define LINUX_GATEWAY_ADDR      0x100
 
index 629eb464d5bacd0d299d9eaad26ef871aed2f573..977f0a4f5ecf2cffec9f147d8999456ed839c01c 100644 (file)
@@ -369,6 +369,7 @@ void __init parisc_setup_cache_timing(void)
 {
        unsigned long rangetime, alltime;
        unsigned long size, start;
+       unsigned long threshold;
 
        alltime = mfctl(16);
        flush_data_cache();
@@ -382,26 +383,30 @@ void __init parisc_setup_cache_timing(void)
        printk(KERN_DEBUG "Whole cache flush %lu cycles, flushing %lu bytes %lu cycles\n",
                alltime, size, rangetime);
 
-       /* Racy, but if we see an intermediate value, it's ok too... */
-       parisc_cache_flush_threshold = size * alltime / rangetime;
-
-       parisc_cache_flush_threshold = L1_CACHE_ALIGN(parisc_cache_flush_threshold);
-       if (!parisc_cache_flush_threshold)
-               parisc_cache_flush_threshold = FLUSH_THRESHOLD;
-
-       if (parisc_cache_flush_threshold > cache_info.dc_size)
-               parisc_cache_flush_threshold = cache_info.dc_size;
-
-       printk(KERN_INFO "Setting cache flush threshold to %lu kB\n",
+       threshold = L1_CACHE_ALIGN(size * alltime / rangetime);
+       if (threshold > cache_info.dc_size)
+               threshold = cache_info.dc_size;
+       if (threshold)
+               parisc_cache_flush_threshold = threshold;
+       printk(KERN_INFO "Cache flush threshold set to %lu KiB\n",
                parisc_cache_flush_threshold/1024);
 
        /* calculate TLB flush threshold */
 
+       /* On SMP machines, skip the TLB measure of kernel text which
+        * has been mapped as huge pages. */
+       if (num_online_cpus() > 1 && !parisc_requires_coherency()) {
+               threshold = max(cache_info.it_size, cache_info.dt_size);
+               threshold *= PAGE_SIZE;
+               threshold /= num_online_cpus();
+               goto set_tlb_threshold;
+       }
+
        alltime = mfctl(16);
        flush_tlb_all();
        alltime = mfctl(16) - alltime;
 
-       size = PAGE_SIZE;
+       size = 0;
        start = (unsigned long) _text;
        rangetime = mfctl(16);
        while (start < (unsigned long) _end) {
@@ -414,13 +419,12 @@ void __init parisc_setup_cache_timing(void)
        printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n",
                alltime, size, rangetime);
 
-       parisc_tlb_flush_threshold = size * alltime / rangetime;
-       parisc_tlb_flush_threshold *= num_online_cpus();
-       parisc_tlb_flush_threshold = PAGE_ALIGN(parisc_tlb_flush_threshold);
-       if (!parisc_tlb_flush_threshold)
-               parisc_tlb_flush_threshold = FLUSH_TLB_THRESHOLD;
+       threshold = PAGE_ALIGN(num_online_cpus() * size * alltime / rangetime);
 
-       printk(KERN_INFO "Setting TLB flush threshold to %lu kB\n",
+set_tlb_threshold:
+       if (threshold)
+               parisc_tlb_flush_threshold = threshold;
+       printk(KERN_INFO "TLB flush threshold set to %lu KiB\n",
                parisc_tlb_flush_threshold/1024);
 }
 
index f8150669b8c6f4e4de827b6b3d2f8dbd586c6593..700e2d2da0969cdfeb872071fe16b5f9c32e82cf 100644 (file)
@@ -873,11 +873,11 @@ static void print_parisc_device(struct parisc_device *dev)
 
        if (dev->num_addrs) {
                int k;
-               printk(", additional addresses: ");
+               pr_cont(", additional addresses: ");
                for (k = 0; k < dev->num_addrs; k++)
-                       printk("0x%lx ", dev->addr[k]);
+                       pr_cont("0x%lx ", dev->addr[k]);
        }
-       printk("\n");
+       pr_cont("\n");
 }
 
 /**
index 545f9d2fe71107edc181170dcac473d9dcec0388..c05d1876d27c4975453194686976c6cb0147531d 100644 (file)
@@ -58,7 +58,7 @@ void __init setup_pdc(void)
        status = pdc_system_map_find_mods(&module_result, &module_path, 0);
        if (status == PDC_OK) {
                pdc_type = PDC_TYPE_SYSTEM_MAP;
-               printk("System Map.\n");
+               pr_cont("System Map.\n");
                return;
        }
 
@@ -77,7 +77,7 @@ void __init setup_pdc(void)
        status = pdc_pat_cell_get_number(&cell_info);
        if (status == PDC_OK) {
                pdc_type = PDC_TYPE_PAT;
-               printk("64 bit PAT.\n");
+               pr_cont("64 bit PAT.\n");
                return;
        }
 #endif
@@ -97,12 +97,12 @@ void __init setup_pdc(void)
        case 0xC:               /* 715/64, at least */
 
                pdc_type = PDC_TYPE_SNAKE;
-               printk("Snake.\n");
+               pr_cont("Snake.\n");
                return;
 
        default:                /* Everything else */
 
-               printk("Unsupported.\n");
+               pr_cont("Unsupported.\n");
                panic("If this is a 64-bit machine, please try a 64-bit kernel.\n");
        }
 }
index 985e06da37f5163fd6ea566024c9f6e82d9db607..adf7187f89515ec69b19461f60ce379e552397dc 100644 (file)
@@ -96,7 +96,7 @@ fitmanyloop:                                  /* Loop if LOOP >= 2 */
 
 fitmanymiddle:                                 /* Loop if LOOP >= 2 */
        addib,COND(>)           -1, %r31, fitmanymiddle /* Adjusted inner loop decr */
-       pitlbe          0(%sr1, %r28)
+       pitlbe          %r0(%sr1, %r28)
        pitlbe,m        %arg1(%sr1, %r28)       /* Last pitlbe and addr adjust */
        addib,COND(>)           -1, %r29, fitmanymiddle /* Middle loop decr */
        copy            %arg3, %r31             /* Re-init inner loop count */
@@ -139,7 +139,7 @@ fdtmanyloop:                                        /* Loop if LOOP >= 2 */
 
 fdtmanymiddle:                                 /* Loop if LOOP >= 2 */
        addib,COND(>)           -1, %r31, fdtmanymiddle /* Adjusted inner loop decr */
-       pdtlbe          0(%sr1, %r28)
+       pdtlbe          %r0(%sr1, %r28)
        pdtlbe,m        %arg1(%sr1, %r28)       /* Last pdtlbe and addr adjust */
        addib,COND(>)           -1, %r29, fdtmanymiddle /* Middle loop decr */
        copy            %arg3, %r31             /* Re-init inner loop count */
@@ -626,12 +626,12 @@ ENTRY_CFI(copy_user_page_asm)
        /* Purge any old translations */
 
 #ifdef CONFIG_PA20
-       pdtlb,l         0(%r28)
-       pdtlb,l         0(%r29)
+       pdtlb,l         %r0(%r28)
+       pdtlb,l         %r0(%r29)
 #else
        tlb_lock        %r20,%r21,%r22
-       pdtlb           0(%r28)
-       pdtlb           0(%r29)
+       pdtlb           %r0(%r28)
+       pdtlb           %r0(%r29)
        tlb_unlock      %r20,%r21,%r22
 #endif
 
@@ -774,10 +774,10 @@ ENTRY_CFI(clear_user_page_asm)
        /* Purge any old translation */
 
 #ifdef CONFIG_PA20
-       pdtlb,l         0(%r28)
+       pdtlb,l         %r0(%r28)
 #else
        tlb_lock        %r20,%r21,%r22
-       pdtlb           0(%r28)
+       pdtlb           %r0(%r28)
        tlb_unlock      %r20,%r21,%r22
 #endif
 
@@ -858,10 +858,10 @@ ENTRY_CFI(flush_dcache_page_asm)
        /* Purge any old translation */
 
 #ifdef CONFIG_PA20
-       pdtlb,l         0(%r28)
+       pdtlb,l         %r0(%r28)
 #else
        tlb_lock        %r20,%r21,%r22
-       pdtlb           0(%r28)
+       pdtlb           %r0(%r28)
        tlb_unlock      %r20,%r21,%r22
 #endif
 
@@ -892,19 +892,10 @@ ENTRY_CFI(flush_dcache_page_asm)
        fdc,m           r31(%r28)
        fdc,m           r31(%r28)
        fdc,m           r31(%r28)
-       cmpb,COND(<<)           %r28, %r25,1b
+       cmpb,COND(<<)   %r28, %r25,1b
        fdc,m           r31(%r28)
 
        sync
-
-#ifdef CONFIG_PA20
-       pdtlb,l         0(%r25)
-#else
-       tlb_lock        %r20,%r21,%r22
-       pdtlb           0(%r25)
-       tlb_unlock      %r20,%r21,%r22
-#endif
-
        bv              %r0(%r2)
        nop
        .exit
@@ -931,13 +922,18 @@ ENTRY_CFI(flush_icache_page_asm)
        depwi           0, 31,PAGE_SHIFT, %r28  /* Clear any offset bits */
 #endif
 
-       /* Purge any old translation */
+       /* Purge any old translation.  Note that the FIC instruction
+        * may use either the instruction or data TLB.  Given that we
+        * have a flat address space, it's not clear which TLB will be
+        * used.  So, we purge both entries.  */
 
 #ifdef CONFIG_PA20
+       pdtlb,l         %r0(%r28)
        pitlb,l         %r0(%sr4,%r28)
 #else
        tlb_lock        %r20,%r21,%r22
-       pitlb           (%sr4,%r28)
+       pdtlb           %r0(%r28)
+       pitlb           %r0(%sr4,%r28)
        tlb_unlock      %r20,%r21,%r22
 #endif
 
@@ -974,15 +970,6 @@ ENTRY_CFI(flush_icache_page_asm)
        fic,m           %r31(%sr4,%r28)
 
        sync
-
-#ifdef CONFIG_PA20
-       pitlb,l         %r0(%sr4,%r25)
-#else
-       tlb_lock        %r20,%r21,%r22
-       pitlb           (%sr4,%r25)
-       tlb_unlock      %r20,%r21,%r22
-#endif
-
        bv              %r0(%r2)
        nop
        .exit
index 02d9ed0f3949f29b0b8db1761e6fb10a43c49414..494ff6e8c88a471288b89aa15737ebae56a6f018 100644 (file)
@@ -95,8 +95,8 @@ static inline int map_pte_uncached(pte_t * pte,
 
                if (!pte_none(*pte))
                        printk(KERN_ERR "map_pte_uncached: page already exists\n");
-               set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
                purge_tlb_start(flags);
+               set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
                pdtlb_kernel(orig_vaddr);
                purge_tlb_end(flags);
                vaddr += PAGE_SIZE;
index 81d6f639194478fa96b33a7f30ba4d612c9cfa8f..2e66a887788e8781bf76b13cbd3fed02e6979259 100644 (file)
@@ -334,6 +334,10 @@ static int __init parisc_init(void)
        /* tell PDC we're Linux. Nevermind failure. */
        pdc_stable_write(0x40, &osid, sizeof(osid));
        
+       /* start with known state */
+       flush_cache_all_local();
+       flush_tlb_all_local(NULL);
+
        processor_init();
 #ifdef CONFIG_SMP
        pr_info("CPU(s): %d out of %d %s at %d.%06d MHz online\n",
index d03422e5f188368f8df5283cedfd4e32845e64df..23de307c3052aa9ecac21fd6c294657fb53de447 100644 (file)
@@ -100,14 +100,12 @@ set_thread_pointer:
        .endr
 
 /* This address must remain fixed at 0x100 for glibc's syscalls to work */
-       .align 256
+       .align LINUX_GATEWAY_ADDR
 linux_gateway_entry:
        gate    .+8, %r0                        /* become privileged */
        mtsp    %r0,%sr4                        /* get kernel space into sr4 */
        mtsp    %r0,%sr5                        /* get kernel space into sr5 */
        mtsp    %r0,%sr6                        /* get kernel space into sr6 */
-       mfsp    %sr7,%r1                        /* save user sr7 */
-       mtsp    %r1,%sr3                        /* and store it in sr3 */
 
 #ifdef CONFIG_64BIT
        /* for now we can *always* set the W bit on entry to the syscall
@@ -133,6 +131,14 @@ linux_gateway_entry:
        depdi   0, 31, 32, %r21
 1:     
 #endif
+
+       /* We use a rsm/ssm pair to prevent sr3 from being clobbered
+        * by external interrupts.
+        */
+       mfsp    %sr7,%r1                        /* save user sr7 */
+       rsm     PSW_SM_I, %r0                   /* disable interrupts */
+       mtsp    %r1,%sr3                        /* and store it in sr3 */
+
        mfctl   %cr30,%r1
        xor     %r1,%r30,%r30                   /* ye olde xor trick */
        xor     %r1,%r30,%r1
@@ -147,6 +153,7 @@ linux_gateway_entry:
         */
 
        mtsp    %r0,%sr7                        /* get kernel space into sr7 */
+       ssm     PSW_SM_I, %r0                   /* enable interrupts */
        STREGM  %r1,FRAME_SIZE(%r30)            /* save r1 (usp) here for now */
        mfctl   %cr30,%r1                       /* get task ptr in %r1 */
        LDREG   TI_TASK(%r1),%r1
@@ -474,11 +481,6 @@ lws_start:
        comiclr,>>      __NR_lws_entries, %r20, %r0
        b,n     lws_exit_nosys
 
-       /* WARNING: Trashing sr2 and sr3 */
-       mfsp    %sr7,%r1                        /* get userspace into sr3 */
-       mtsp    %r1,%sr3
-       mtsp    %r0,%sr2                        /* get kernel space into sr2 */
-
        /* Load table start */
        ldil    L%lws_table, %r1
        ldo     R%lws_table(%r1), %r28  /* Scratch use of r28 */
@@ -627,9 +629,9 @@ cas_action:
        stw     %r1, 4(%sr2,%r20)
 #endif
        /* The load and store could fail */
-1:     ldw,ma  0(%sr3,%r26), %r28
+1:     ldw,ma  0(%r26), %r28
        sub,<>  %r28, %r25, %r0
-2:     stw,ma  %r24, 0(%sr3,%r26)
+2:     stw,ma  %r24, 0(%r26)
        /* Free lock */
        stw,ma  %r20, 0(%sr2,%r20)
 #if ENABLE_LWS_DEBUG
@@ -706,9 +708,9 @@ lws_compare_and_swap_2:
        nop
 
        /* 8bit load */
-4:     ldb     0(%sr3,%r25), %r25
+4:     ldb     0(%r25), %r25
        b       cas2_lock_start
-5:     ldb     0(%sr3,%r24), %r24
+5:     ldb     0(%r24), %r24
        nop
        nop
        nop
@@ -716,9 +718,9 @@ lws_compare_and_swap_2:
        nop
 
        /* 16bit load */
-6:     ldh     0(%sr3,%r25), %r25
+6:     ldh     0(%r25), %r25
        b       cas2_lock_start
-7:     ldh     0(%sr3,%r24), %r24
+7:     ldh     0(%r24), %r24
        nop
        nop
        nop
@@ -726,9 +728,9 @@ lws_compare_and_swap_2:
        nop
 
        /* 32bit load */
-8:     ldw     0(%sr3,%r25), %r25
+8:     ldw     0(%r25), %r25
        b       cas2_lock_start
-9:     ldw     0(%sr3,%r24), %r24
+9:     ldw     0(%r24), %r24
        nop
        nop
        nop
@@ -737,14 +739,14 @@ lws_compare_and_swap_2:
 
        /* 64bit load */
 #ifdef CONFIG_64BIT
-10:    ldd     0(%sr3,%r25), %r25
-11:    ldd     0(%sr3,%r24), %r24
+10:    ldd     0(%r25), %r25
+11:    ldd     0(%r24), %r24
 #else
        /* Load new value into r22/r23 - high/low */
-10:    ldw     0(%sr3,%r25), %r22
-11:    ldw     4(%sr3,%r25), %r23
+10:    ldw     0(%r25), %r22
+11:    ldw     4(%r25), %r23
        /* Load new value into fr4 for atomic store later */
-12:    flddx   0(%sr3,%r24), %fr4
+12:    flddx   0(%r24), %fr4
 #endif
 
 cas2_lock_start:
@@ -794,30 +796,30 @@ cas2_action:
        ldo     1(%r0),%r28
 
        /* 8bit CAS */
-13:    ldb,ma  0(%sr3,%r26), %r29
+13:    ldb,ma  0(%r26), %r29
        sub,=   %r29, %r25, %r0
        b,n     cas2_end
-14:    stb,ma  %r24, 0(%sr3,%r26)
+14:    stb,ma  %r24, 0(%r26)
        b       cas2_end
        copy    %r0, %r28
        nop
        nop
 
        /* 16bit CAS */
-15:    ldh,ma  0(%sr3,%r26), %r29
+15:    ldh,ma  0(%r26), %r29
        sub,=   %r29, %r25, %r0
        b,n     cas2_end
-16:    sth,ma  %r24, 0(%sr3,%r26)
+16:    sth,ma  %r24, 0(%r26)
        b       cas2_end
        copy    %r0, %r28
        nop
        nop
 
        /* 32bit CAS */
-17:    ldw,ma  0(%sr3,%r26), %r29
+17:    ldw,ma  0(%r26), %r29
        sub,=   %r29, %r25, %r0
        b,n     cas2_end
-18:    stw,ma  %r24, 0(%sr3,%r26)
+18:    stw,ma  %r24, 0(%r26)
        b       cas2_end
        copy    %r0, %r28
        nop
@@ -825,22 +827,22 @@ cas2_action:
 
        /* 64bit CAS */
 #ifdef CONFIG_64BIT
-19:    ldd,ma  0(%sr3,%r26), %r29
+19:    ldd,ma  0(%r26), %r29
        sub,*=  %r29, %r25, %r0
        b,n     cas2_end
-20:    std,ma  %r24, 0(%sr3,%r26)
+20:    std,ma  %r24, 0(%r26)
        copy    %r0, %r28
 #else
        /* Compare first word */
-19:    ldw,ma  0(%sr3,%r26), %r29
+19:    ldw,ma  0(%r26), %r29
        sub,=   %r29, %r22, %r0
        b,n     cas2_end
        /* Compare second word */
-20:    ldw,ma  4(%sr3,%r26), %r29
+20:    ldw,ma  4(%r26), %r29
        sub,=   %r29, %r23, %r0
        b,n     cas2_end
        /* Perform the store */
-21:    fstdx   %fr4, 0(%sr3,%r26)
+21:    fstdx   %fr4, 0(%r26)
        copy    %r0, %r28
 #endif
 
index 9b63b876a13a4b6ad422f7ae69fc49fed70eb1be..325f30d82b6434368425d652402fabf66fd4f8ee 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/sched.h>
+#include <linux/sched_clock.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/string.h>
 
 static unsigned long clocktick __read_mostly;  /* timer cycles per tick */
 
-#ifndef CONFIG_64BIT
-/*
- * The processor-internal cycle counter (Control Register 16) is used as time
- * source for the sched_clock() function.  This register is 64bit wide on a
- * 64-bit kernel and 32bit on a 32-bit kernel. Since sched_clock() always
- * requires a 64bit counter we emulate on the 32-bit kernel the higher 32bits
- * with a per-cpu variable which we increase every time the counter
- * wraps-around (which happens every ~4 secounds).
- */
-static DEFINE_PER_CPU(unsigned long, cr16_high_32_bits);
-#endif
-
 /*
  * We keep time on PA-RISC Linux by using the Interval Timer which is
  * a pair of registers; one is read-only and one is write-only; both
@@ -121,12 +110,6 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
         */
        mtctl(next_tick, 16);
 
-#if !defined(CONFIG_64BIT)
-       /* check for overflow on a 32bit kernel (every ~4 seconds). */
-       if (unlikely(next_tick < now))
-               this_cpu_inc(cr16_high_32_bits);
-#endif
-
        /* Skip one clocktick on purpose if we missed next_tick.
         * The new CR16 must be "later" than current CR16 otherwise
         * itimer would not fire until CR16 wrapped - e.g 4 seconds
@@ -208,7 +191,7 @@ EXPORT_SYMBOL(profile_pc);
 
 /* clock source code */
 
-static cycle_t read_cr16(struct clocksource *cs)
+static cycle_t notrace read_cr16(struct clocksource *cs)
 {
        return get_cycles();
 }
@@ -287,26 +270,9 @@ void read_persistent_clock(struct timespec *ts)
 }
 
 
-/*
- * sched_clock() framework
- */
-
-static u32 cyc2ns_mul __read_mostly;
-static u32 cyc2ns_shift __read_mostly;
-
-u64 sched_clock(void)
+static u64 notrace read_cr16_sched_clock(void)
 {
-       u64 now;
-
-       /* Get current cycle counter (Control Register 16). */
-#ifdef CONFIG_64BIT
-       now = mfctl(16);
-#else
-       now = mfctl(16) + (((u64) this_cpu_read(cr16_high_32_bits)) << 32);
-#endif
-
-       /* return the value in ns (cycles_2_ns) */
-       return mul_u64_u32_shr(now, cyc2ns_mul, cyc2ns_shift);
+       return get_cycles();
 }
 
 
@@ -316,17 +282,16 @@ u64 sched_clock(void)
 
 void __init time_init(void)
 {
-       unsigned long current_cr16_khz;
+       unsigned long cr16_hz;
 
-       current_cr16_khz = PAGE0->mem_10msec/10;  /* kHz */
        clocktick = (100 * PAGE0->mem_10msec) / HZ;
-
-       /* calculate mult/shift values for cr16 */
-       clocks_calc_mult_shift(&cyc2ns_mul, &cyc2ns_shift, current_cr16_khz,
-                               NSEC_PER_MSEC, 0);
-
        start_cpu_itimer();     /* get CPU 0 started */
 
+       cr16_hz = 100 * PAGE0->mem_10msec;  /* Hz */
+
        /* register at clocksource framework */
-       clocksource_register_khz(&clocksource_cr16, current_cr16_khz);
+       clocksource_register_hz(&clocksource_cr16, cr16_hz);
+
+       /* register as sched_clock source */
+       sched_clock_register(read_cr16_sched_clock, BITS_PER_LONG, cr16_hz);
 }
index eae2dc8bc218165242f4406df9a6273755b60770..9d47f2efa830c220c68ffa11d29d6efaa3fa84cc 100644 (file)
@@ -100,7 +100,8 @@ src-wlib-y := string.S crt0.S crtsavres.S stdio.c decompress.c main.c \
                ns16550.c serial.c simple_alloc.c div64.S util.S \
                elf_util.c $(zlib-y) devtree.c stdlib.c \
                oflib.c ofconsole.c cuboot.c mpsc.c cpm-serial.c \
-               uartlite.c mpc52xx-psc.c opal.c opal-calls.S
+               uartlite.c mpc52xx-psc.c opal.c
+src-wlib-$(CONFIG_PPC64_BOOT_WRAPPER) +=  opal-calls.S
 src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c
 src-wlib-$(CONFIG_44x) += 4xx.c ebony.c bamboo.c
 src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c fsl-soc.c
index f7a184b6c35b4ad00414720316cfbbf1d50fc704..78aaf4ffd7ab07156990a4d5a68118dec6944213 100644 (file)
@@ -32,9 +32,16 @@ static struct addr_range prep_kernel(void)
        void *addr = 0;
        struct elf_info ei;
        long len;
+       int uncompressed_image = 0;
 
-       partial_decompress(vmlinuz_addr, vmlinuz_size,
+       len = partial_decompress(vmlinuz_addr, vmlinuz_size,
                elfheader, sizeof(elfheader), 0);
+       /* assume uncompressed data if -1 is returned */
+       if (len == -1) {
+               uncompressed_image = 1;
+               memcpy(elfheader, vmlinuz_addr, sizeof(elfheader));
+               printf("No valid compressed data found, assume uncompressed data\n\r");
+       }
 
        if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
                fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
@@ -67,6 +74,13 @@ static struct addr_range prep_kernel(void)
                                        "device tree\n\r");
        }
 
+       if (uncompressed_image) {
+               memcpy(addr, vmlinuz_addr + ei.elfoffset, ei.loadsize);
+               printf("0x%lx bytes of uncompressed data copied\n\r",
+                      ei.loadsize);
+               goto out;
+       }
+
        /* Finally, decompress the kernel */
        printf("Decompressing (0x%p <- 0x%p:0x%p)...\n\r", addr,
               vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
@@ -82,7 +96,7 @@ static struct addr_range prep_kernel(void)
                         len, ei.loadsize);
 
        printf("Done! Decompressed 0x%lx bytes\n\r", len);
-
+out:
        flush_cache(addr, ei.loadsize);
 
        return (struct addr_range){addr, ei.memsize};
@@ -218,8 +232,12 @@ void start(void)
                console_ops.close();
 
        kentry = (kernel_entry_t) vmlinux.addr;
-       if (ft_addr)
-               kentry(ft_addr, 0, NULL);
+       if (ft_addr) {
+               if(platform_ops.kentry)
+                       platform_ops.kentry(ft_addr, vmlinux.addr);
+               else
+                       kentry(ft_addr, 0, NULL);
+       }
        else
                kentry((unsigned long)initrd.addr, initrd.size,
                       loader_info.promptr);
index ff2f1b97bc5323f78bbfdd038fccebdde45a4432..2a99fc9a3ccf368d5176d799133e652ffb70ca87 100644 (file)
 
        .text
 
+       .globl opal_kentry
+opal_kentry:
+       /* r3 is the fdt ptr */
+       mtctr r4
+       li      r4, 0
+       li      r5, 0
+       li      r6, 0
+       li      r7, 0
+       ld      r11,opal@got(r2)
+       ld      r8,0(r11)
+       ld      r9,8(r11)
+       bctr
+
 #define OPAL_CALL(name, token)                         \
        .globl name;                                    \
 name:                                                  \
index 1f37e1c1d6d88b9cd0a88795a12e8651389dc483..0272570d02de15ba70363809c987ca7efd97dd99 100644 (file)
@@ -13,7 +13,7 @@
 #include <libfdt.h>
 #include "../include/asm/opal-api.h"
 
-#ifdef __powerpc64__
+#ifdef CONFIG_PPC64_BOOT_WRAPPER
 
 /* Global OPAL struct used by opal-call.S */
 struct opal {
@@ -23,14 +23,25 @@ struct opal {
 
 static u32 opal_con_id;
 
+/* see opal-wrappers.S */
 int64_t opal_console_write(int64_t term_number, u64 *length, const u8 *buffer);
 int64_t opal_console_read(int64_t term_number, uint64_t *length, u8 *buffer);
 int64_t opal_console_write_buffer_space(uint64_t term_number, uint64_t *length);
 int64_t opal_console_flush(uint64_t term_number);
 int64_t opal_poll_events(uint64_t *outstanding_event_mask);
 
+void opal_kentry(unsigned long fdt_addr, void *vmlinux_addr);
+
 static int opal_con_open(void)
 {
+       /*
+        * When OPAL loads the boot kernel it stashes the OPAL base and entry
+        * address in r8 and r9 so the kernel can use the OPAL console
+        * before unflattening the devicetree. While executing the wrapper will
+        * probably trash r8 and r9 so this kentry hook restores them before
+        * entering the decompressed kernel.
+        */
+       platform_ops.kentry = opal_kentry;
        return 0;
 }
 
index 309d1b127e966f8161d7940eaf30e2f68b2b47e6..fad1862f4b2d3904360aa68431177dbc79621f99 100644 (file)
@@ -30,6 +30,7 @@ struct platform_ops {
        void *  (*realloc)(void *ptr, unsigned long size);
        void    (*exit)(void);
        void *  (*vmlinux_alloc)(unsigned long size);
+       void    (*kentry)(unsigned long fdt_addr, void *vmlinux_addr);
 };
 extern struct platform_ops platform_ops;
 
index d1492736d85223d54913eef6c2014d915cdb7f78..e0baba1535e6b08ab9350d64c51507ebfbf1630a 100644 (file)
 
 #include <linux/threads.h>
 #include <linux/kprobes.h>
+#include <asm/cacheflush.h>
+#include <asm/checksum.h>
+#include <asm/uaccess.h>
+#include <asm/epapr_hcalls.h>
 
 #include <uapi/asm/ucontext.h>
 
@@ -109,4 +113,12 @@ void early_setup_secondary(void);
 /* time */
 void accumulate_stolen_time(void);
 
+/* misc runtime */
+extern u64 __bswapdi2(u64);
+extern s64 __lshrdi3(s64, int);
+extern s64 __ashldi3(s64, int);
+extern s64 __ashrdi3(s64, int);
+extern int __cmpdi2(s64, s64);
+extern int __ucmpdi2(u64, u64);
+
 #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
index ee655ed1ff1bc7eae352be8887936e168f7ab58f..1e8fceb308a518950918e1ea7d9102eb313f66ee 100644 (file)
@@ -53,10 +53,8 @@ static inline __sum16 csum_fold(__wsum sum)
        return (__force __sum16)(~((__force u32)sum + tmp) >> 16);
 }
 
-static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
-                                     unsigned short len,
-                                     unsigned short proto,
-                                     __wsum sum)
+static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
+                                       __u8 proto, __wsum sum)
 {
 #ifdef __powerpc64__
        unsigned long s = (__force u32)sum;
@@ -83,10 +81,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
  * computes the checksum of the TCP/UDP pseudo-header
  * returns a 16-bit checksum, already complemented
  */
-static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
-                                       unsigned short len,
-                                       unsigned short proto,
-                                       __wsum sum)
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
+                                       __u8 proto, __wsum sum)
 {
        return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
 }
index 01b8a13f022467be64ccd46f248344bdf96e9a41..3919332965af04bf98f2b77b7f4ec722d5acf8da 100644 (file)
@@ -26,7 +26,7 @@ extern u64 pnv_first_deep_stop_state;
        std     r0,0(r1);                                       \
        ptesync;                                                \
        ld      r0,0(r1);                                       \
-1:     cmp     cr0,r0,r0;                                      \
+1:     cmpd    cr0,r0,r0;                                      \
        bne     1b;                                             \
        IDLE_INST;                                              \
        b       .
index 2e4e7d878c8eeda322d701cb3f407d67ecff0a58..9a3eee66129766d84d8bd5063fd8ecd142e8fc21 100644 (file)
  */
 #define LOAD_HANDLER(reg, label)                                       \
        ld      reg,PACAKBASE(r13);     /* get high part of &label */   \
-       ori     reg,reg,(FIXED_SYMBOL_ABS_ADDR(label))@l;
+       ori     reg,reg,FIXED_SYMBOL_ABS_ADDR(label);
+
+#define __LOAD_HANDLER(reg, label)                                     \
+       ld      reg,PACAKBASE(r13);                                     \
+       ori     reg,reg,(ABS_ADDR(label))@l;
 
 /* Exception register prefixes */
 #define EXC_HV H
@@ -154,14 +158,17 @@ BEGIN_FTR_SECTION_NESTED(943)                                             \
        std     ra,offset(r13);                                         \
 END_FTR_SECTION_NESTED(ftr,ftr,943)
 
-#define EXCEPTION_PROLOG_0(area)                                       \
-       GET_PACA(r13);                                                  \
+#define EXCEPTION_PROLOG_0_PACA(area)                                  \
        std     r9,area+EX_R9(r13);     /* save r9 */                   \
        OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);                     \
        HMT_MEDIUM;                                                     \
        std     r10,area+EX_R10(r13);   /* save r10 - r12 */            \
        OPT_GET_SPR(r10, SPRN_CFAR, CPU_FTR_CFAR)
 
+#define EXCEPTION_PROLOG_0(area)                                       \
+       GET_PACA(r13);                                                  \
+       EXCEPTION_PROLOG_0_PACA(area)
+
 #define __EXCEPTION_PROLOG_1(area, extra, vec)                         \
        OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR);         \
        OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR);          \
@@ -192,6 +199,12 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
        EXCEPTION_PROLOG_1(area, extra, vec);                           \
        EXCEPTION_PROLOG_PSERIES_1(label, h);
 
+/* Have the PACA in r13 already */
+#define EXCEPTION_PROLOG_PSERIES_PACA(area, label, h, extra, vec)      \
+       EXCEPTION_PROLOG_0_PACA(area);                                  \
+       EXCEPTION_PROLOG_1(area, extra, vec);                           \
+       EXCEPTION_PROLOG_PSERIES_1(label, h);
+
 #define __KVMTEST(h, n)                                                        \
        lbz     r10,HSTATE_IN_GUEST(r13);                               \
        cmpwi   r10,0;                                                  \
@@ -208,6 +221,18 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
 #define kvmppc_interrupt kvmppc_interrupt_pr
 #endif
 
+#ifdef CONFIG_RELOCATABLE
+#define BRANCH_TO_COMMON(reg, label)                                   \
+       __LOAD_HANDLER(reg, label);                                     \
+       mtctr   reg;                                                    \
+       bctr
+
+#else
+#define BRANCH_TO_COMMON(reg, label)                                   \
+       b       label
+
+#endif
+
 #define __KVM_HANDLER_PROLOG(area, n)                                  \
        BEGIN_FTR_SECTION_NESTED(947)                                   \
        ld      r10,area+EX_CFAR(r13);                                  \
index e88368354e499caa901020303d4d969d120ab60b..e311c25751a4111d20f8bef1165ff52934a18576 100644 (file)
  * Individual features below.
  */
 
+/*
+ * Kernel read only support.
+ * We added the ppp value 0b110 in ISA 2.04.
+ */
+#define MMU_FTR_KERNEL_RO              ASM_CONST(0x00004000)
+
 /*
  * We need to clear top 16bits of va (from the remaining 64 bits )in
  * tlbie* instructions
 #define MMU_FTRS_POWER4                MMU_FTRS_DEFAULT_HPTE_ARCH_V2
 #define MMU_FTRS_PPC970                MMU_FTRS_POWER4 | MMU_FTR_TLBIE_CROP_VA
 #define MMU_FTRS_POWER5                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
-#define MMU_FTRS_POWER6                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
-#define MMU_FTRS_POWER7                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
-#define MMU_FTRS_POWER8                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
-#define MMU_FTRS_POWER9                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
+#define MMU_FTRS_POWER6                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
+#define MMU_FTRS_POWER7                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
+#define MMU_FTRS_POWER8                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
+#define MMU_FTRS_POWER9                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
 #define MMU_FTRS_CELL          MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
                                MMU_FTR_CI_LARGE_PAGE
 #define MMU_FTRS_PA6T          MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
index 0132831b3081934254b71e4f032d755a01a1d16a..c56ea8c84abb1771ff65f66ba91ffff02bff5fae 100644 (file)
 
 #define PPC_SLBIA(IH)  stringify_in_c(.long PPC_INST_SLBIA | \
                                       ((IH & 0x7) << 21))
+#define PPC_INVALIDATE_ERAT    PPC_SLBIA(7)
 
 #endif /* _ASM_POWERPC_PPC_OPCODE_H */
index 9cd4e8cbc78c6ca6eac7948e0cf4458d0f827fcd..9e1499f98deff5299e7a666313749c8b4ebad0b1 100644 (file)
 #define     LPCR_PECE0         ASM_CONST(0x0000000000004000)   /* ext. exceptions can cause exit */
 #define     LPCR_PECE1         ASM_CONST(0x0000000000002000)   /* decrementer can cause exit */
 #define     LPCR_PECE2         ASM_CONST(0x0000000000001000)   /* machine check etc can cause exit */
+#define     LPCR_PECE_HVEE     ASM_CONST(0x0000400000000000)   /* P9 Wakeup on HV interrupts */
 #define   LPCR_MER             ASM_CONST(0x0000000000000800)   /* Mediated External Exception */
 #define   LPCR_MER_SH          11
 #define   LPCR_TC              ASM_CONST(0x0000000000000200)   /* Translation control */
index f6f68f73e8581147772bad3100f74ed5950987bd..99e1397b71dac78dae0cc2b98eefd40cf90947ec 100644 (file)
@@ -52,11 +52,23 @@ static inline int mm_is_core_local(struct mm_struct *mm)
        return cpumask_subset(mm_cpumask(mm),
                              topology_sibling_cpumask(smp_processor_id()));
 }
+
+static inline int mm_is_thread_local(struct mm_struct *mm)
+{
+       return cpumask_equal(mm_cpumask(mm),
+                             cpumask_of(smp_processor_id()));
+}
+
 #else
 static inline int mm_is_core_local(struct mm_struct *mm)
 {
        return 1;
 }
+
+static inline int mm_is_thread_local(struct mm_struct *mm)
+{
+       return 1;
+}
 #endif
 
 #endif /* __KERNEL__ */
index cf12c580f6b286b957b0280d8174cc3d8c203d2f..e8cdfec8d5125c531c45b7ffd250955ad68021af 100644 (file)
 
 #define __NR__exit __NR_exit
 
+#define __IGNORE_pkey_mprotect
+#define __IGNORE_pkey_alloc
+#define __IGNORE_pkey_free
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
index 52ff3f025437947484d7567141b5d3802cc887c2..37c027ca83b2b172a07a9ed01b23ec3e34baffff 100644 (file)
@@ -98,8 +98,8 @@ _GLOBAL(__setup_cpu_power9)
        li      r0,0
        mtspr   SPRN_LPID,r0
        mfspr   r3,SPRN_LPCR
-       ori     r3, r3, LPCR_PECEDH
-       ori     r3, r3, LPCR_HVICE
+       LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE)
+       or      r3, r3, r4
        bl      __init_LPCR
        bl      __init_HFSCR
        bl      __init_tlb_power9
@@ -118,8 +118,8 @@ _GLOBAL(__restore_cpu_power9)
        li      r0,0
        mtspr   SPRN_LPID,r0
        mfspr   r3,SPRN_LPCR
-       ori     r3, r3, LPCR_PECEDH
-       ori     r3, r3, LPCR_HVICE
+       LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE)
+       or      r3, r3, r4
        bl      __init_LPCR
        bl      __init_HFSCR
        bl      __init_tlb_power9
index a62be72da274de3993a4b28cfbad7938d5502559..5c31369435f24200ae8c06bc69a8795b12ffd8e3 100644 (file)
@@ -671,8 +671,10 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
 
        /* Clear frozen state */
        rc = eeh_clear_pe_frozen_state(pe, false);
-       if (rc)
+       if (rc) {
+               pci_unlock_rescan_remove();
                return rc;
+       }
 
        /* Give the system 5 seconds to finish running the user-space
         * hotplug shutdown scripts, e.g. ifdown for ethernet.  Yes,
index f129408c602290d7ccf5870e2b12b46b0380bea5..1ba82ea9023093ae3d58eedba4b9542bae137047 100644 (file)
@@ -95,19 +95,40 @@ __start_interrupts:
 /* No virt vectors corresponding with 0x0..0x100 */
 EXC_VIRT_NONE(0x4000, 0x4100)
 
-EXC_REAL_BEGIN(system_reset, 0x100, 0x200)
-       SET_SCRATCH0(r13)
+
 #ifdef CONFIG_PPC_P7_NAP
-BEGIN_FTR_SECTION
-       /* Running native on arch 2.06 or later, check if we are
-        * waking up from nap/sleep/winkle.
+       /*
+        * If running native on arch 2.06 or later, check if we are waking up
+        * from nap/sleep/winkle, and branch to idle handler.
         */
-       mfspr   r13,SPRN_SRR1
-       rlwinm. r13,r13,47-31,30,31
-       beq     9f
+#define IDLETEST(n)                                                    \
+       BEGIN_FTR_SECTION ;                                             \
+       mfspr   r10,SPRN_SRR1 ;                                         \
+       rlwinm. r10,r10,47-31,30,31 ;                                   \
+       beq-    1f ;                                                    \
+       cmpwi   cr3,r10,2 ;                                             \
+       BRANCH_TO_COMMON(r10, system_reset_idle_common) ;               \
+1:                                                                     \
+       END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
+#else
+#define IDLETEST NOTEST
+#endif
 
-       cmpwi   cr3,r13,2
+EXC_REAL_BEGIN(system_reset, 0x100, 0x200)
+       SET_SCRATCH0(r13)
        GET_PACA(r13)
+       clrrdi  r13,r13,1 /* Last bit of HSPRG0 is set if waking from winkle */
+       EXCEPTION_PROLOG_PSERIES_PACA(PACA_EXGEN, system_reset_common, EXC_STD,
+                                IDLETEST, 0x100)
+
+EXC_REAL_END(system_reset, 0x100, 0x200)
+EXC_VIRT_NONE(0x4100, 0x4200)
+
+#ifdef CONFIG_PPC_P7_NAP
+EXC_COMMON_BEGIN(system_reset_idle_common)
+BEGIN_FTR_SECTION
+       GET_PACA(r13) /* Restore HSPRG0 to get the winkle bit in r13 */
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        bl      pnv_restore_hyp_resource
 
        li      r0,PNV_THREAD_RUNNING
@@ -130,14 +151,8 @@ BEGIN_FTR_SECTION
        blt     cr3,2f
        b       pnv_wakeup_loss
 2:     b       pnv_wakeup_noloss
+#endif
 
-9:
-END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
-#endif /* CONFIG_PPC_P7_NAP */
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
-                                NOTEST, 0x100)
-EXC_REAL_END(system_reset, 0x100, 0x200)
-EXC_VIRT_NONE(0x4100, 0x4200)
 EXC_COMMON(system_reset_common, 0x100, system_reset_exception)
 
 #ifdef CONFIG_PPC_PSERIES
@@ -159,7 +174,7 @@ EXC_REAL_BEGIN(machine_check, 0x200, 0x300)
        SET_SCRATCH0(r13)               /* save r13 */
        /*
         * Running native on arch 2.06 or later, we may wakeup from winkle
-        * inside machine check. If yes, then last bit of HSPGR0 would be set
+        * inside machine check. If yes, then last bit of HSPRG0 would be set
         * to 1. Hence clear it unconditionally.
         */
        GET_PACA(r13)
@@ -378,7 +393,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
        /*
         * Go back to winkle. Please note that this thread was woken up in
         * machine check from winkle and have not restored the per-subcore
-        * state. Hence before going back to winkle, set last bit of HSPGR0
+        * state. Hence before going back to winkle, set last bit of HSPRG0
         * to 1. This will make sure that if this thread gets woken up
         * again at reset vector 0x100 then it will get chance to restore
         * the subcore state.
@@ -817,10 +832,8 @@ EXC_VIRT(trap_0b, 0x4b00, 0x4c00, 0xb00)
 TRAMP_KVM(PACA_EXGEN, 0xb00)
 EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
 
-
-#define LOAD_SYSCALL_HANDLER(reg)                              \
-       ld      reg,PACAKBASE(r13);                             \
-       ori     reg,reg,(ABS_ADDR(system_call_common))@l;
+#define LOAD_SYSCALL_HANDLER(reg)                                      \
+       __LOAD_HANDLER(reg, system_call_common)
 
 /* Syscall routine is used twice, in reloc-off and reloc-on paths */
 #define SYSCALL_PSERIES_1                                      \
index 9781c69eae5767adc9fdde54232e4df1329e7b92..03d089b3ed726faeb69d3121e27191ed834899bf 100644 (file)
@@ -275,7 +275,7 @@ int hw_breakpoint_handler(struct die_args *args)
        if (!stepped) {
                WARN(1, "Unable to handle hardware breakpoint. Breakpoint at "
                        "0x%lx will be disabled.", info->address);
-               perf_event_disable(bp);
+               perf_event_disable_inatomic(bp);
                goto out;
        }
        /*
index bd739fed26e3203aae73807399c43a939c248d38..72dac0b58061f023db4a4c8a4b6badd66bcd0b70 100644 (file)
@@ -90,6 +90,7 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300)
  * Threads will spin in HMT_LOW until the lock bit is cleared.
  * r14 - pointer to core_idle_state
  * r15 - used to load contents of core_idle_state
+ * r9  - used as a temporary variable
  */
 
 core_idle_lock_held:
@@ -99,6 +100,8 @@ core_idle_lock_held:
        bne     3b
        HMT_MEDIUM
        lwarx   r15,0,r14
+       andi.   r9,r15,PNV_CORE_IDLE_LOCK_BIT
+       bne     core_idle_lock_held
        blr
 
 /*
@@ -163,12 +166,6 @@ _GLOBAL(pnv_powersave_common)
        std     r9,_MSR(r1)
        std     r1,PACAR1(r13)
 
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-       /* Tell KVM we're entering idle */
-       li      r4,KVM_HWTHREAD_IN_IDLE
-       stb     r4,HSTATE_HWTHREAD_STATE(r13)
-#endif
-
        /*
         * Go to real mode to do the nap, as required by the architecture.
         * Also, we need to be in real mode before setting hwthread_state,
@@ -185,6 +182,26 @@ _GLOBAL(pnv_powersave_common)
 
        .globl pnv_enter_arch207_idle_mode
 pnv_enter_arch207_idle_mode:
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       /* Tell KVM we're entering idle */
+       li      r4,KVM_HWTHREAD_IN_IDLE
+       /******************************************************/
+       /*  N O T E   W E L L    ! ! !    N O T E   W E L L   */
+       /* The following store to HSTATE_HWTHREAD_STATE(r13)  */
+       /* MUST occur in real mode, i.e. with the MMU off,    */
+       /* and the MMU must stay off until we clear this flag */
+       /* and test HSTATE_HWTHREAD_REQ(r13) in the system    */
+       /* reset interrupt vector in exceptions-64s.S.        */
+       /* The reason is that another thread can switch the   */
+       /* MMU to a guest context whenever this flag is set   */
+       /* to KVM_HWTHREAD_IN_IDLE, and if the MMU was on,    */
+       /* that would potentially cause this thread to start  */
+       /* executing instructions from guest memory in        */
+       /* hypervisor mode, leading to a host crash or data   */
+       /* corruption, or worse.                              */
+       /******************************************************/
+       stb     r4,HSTATE_HWTHREAD_STATE(r13)
+#endif
        stb     r3,PACA_THREAD_IDLE_STATE(r13)
        cmpwi   cr3,r3,PNV_THREAD_SLEEP
        bge     cr3,2f
@@ -250,6 +267,12 @@ enter_winkle:
  * r3 - requested stop state
  */
 power_enter_stop:
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       /* Tell KVM we're entering idle */
+       li      r4,KVM_HWTHREAD_IN_IDLE
+       /* DO THIS IN REAL MODE!  See comment above. */
+       stb     r4,HSTATE_HWTHREAD_STATE(r13)
+#endif
 /*
  * Check if the requested state is a deep idle state.
  */
index 9e7c10fe205f7f5dc3415f54d5abf7bf2a2105b3..49a680d5ae3740041b8819095d3815dda4930417 100644 (file)
@@ -1012,7 +1012,7 @@ void restore_tm_state(struct pt_regs *regs)
        /* Ensure that restore_math() will restore */
        if (msr_diff & MSR_FP)
                current->thread.load_fp = 1;
-#ifdef CONFIG_ALIVEC
+#ifdef CONFIG_ALTIVEC
        if (cpu_has_feature(CPU_FTR_ALTIVEC) && msr_diff & MSR_VEC)
                current->thread.load_vec = 1;
 #endif
@@ -1215,7 +1215,7 @@ static void show_instructions(struct pt_regs *regs)
                int instr;
 
                if (!(i % 8))
-                       printk("\n");
+                       pr_cont("\n");
 
 #if !defined(CONFIG_BOOKE)
                /* If executing with the IMMU off, adjust pc rather
@@ -1227,18 +1227,18 @@ static void show_instructions(struct pt_regs *regs)
 
                if (!__kernel_text_address(pc) ||
                     probe_kernel_address((unsigned int __user *)pc, instr)) {
-                       printk(KERN_CONT "XXXXXXXX ");
+                       pr_cont("XXXXXXXX ");
                } else {
                        if (regs->nip == pc)
-                               printk(KERN_CONT "<%08x> ", instr);
+                               pr_cont("<%08x> ", instr);
                        else
-                               printk(KERN_CONT "%08x ", instr);
+                               pr_cont("%08x ", instr);
                }
 
                pc += sizeof(int);
        }
 
-       printk("\n");
+       pr_cont("\n");
 }
 
 struct regbit {
@@ -1282,7 +1282,7 @@ static void print_bits(unsigned long val, struct regbit *bits, const char *sep)
 
        for (; bits->bit; ++bits)
                if (val & bits->bit) {
-                       printk("%s%s", s, bits->name);
+                       pr_cont("%s%s", s, bits->name);
                        s = sep;
                }
 }
@@ -1305,9 +1305,9 @@ static void print_tm_bits(unsigned long val)
  *   T: Transactional  (bit 34)
  */
        if (val & (MSR_TM | MSR_TS_S | MSR_TS_T)) {
-               printk(",TM[");
+               pr_cont(",TM[");
                print_bits(val, msr_tm_bits, "");
-               printk("]");
+               pr_cont("]");
        }
 }
 #else
@@ -1316,10 +1316,10 @@ static void print_tm_bits(unsigned long val) {}
 
 static void print_msr_bits(unsigned long val)
 {
-       printk("<");
+       pr_cont("<");
        print_bits(val, msr_bits, ",");
        print_tm_bits(val);
-       printk(">");
+       pr_cont(">");
 }
 
 #ifdef CONFIG_PPC64
@@ -1347,29 +1347,29 @@ void show_regs(struct pt_regs * regs)
        printk("  CR: %08lx  XER: %08lx\n", regs->ccr, regs->xer);
        trap = TRAP(regs);
        if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR))
-               printk("CFAR: "REG" ", regs->orig_gpr3);
+               pr_cont("CFAR: "REG" ", regs->orig_gpr3);
        if (trap == 0x200 || trap == 0x300 || trap == 0x600)
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
-               printk("DEAR: "REG" ESR: "REG" ", regs->dar, regs->dsisr);
+               pr_cont("DEAR: "REG" ESR: "REG" ", regs->dar, regs->dsisr);
 #else
-               printk("DAR: "REG" DSISR: %08lx ", regs->dar, regs->dsisr);
+               pr_cont("DAR: "REG" DSISR: %08lx ", regs->dar, regs->dsisr);
 #endif
 #ifdef CONFIG_PPC64
-       printk("SOFTE: %ld ", regs->softe);
+       pr_cont("SOFTE: %ld ", regs->softe);
 #endif
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        if (MSR_TM_ACTIVE(regs->msr))
-               printk("\nPACATMSCRATCH: %016llx ", get_paca()->tm_scratch);
+               pr_cont("\nPACATMSCRATCH: %016llx ", get_paca()->tm_scratch);
 #endif
 
        for (i = 0;  i < 32;  i++) {
                if ((i % REGS_PER_LINE) == 0)
-                       printk("\nGPR%02d: ", i);
-               printk(REG " ", regs->gpr[i]);
+                       pr_cont("\nGPR%02d: ", i);
+               pr_cont(REG " ", regs->gpr[i]);
                if (i == LAST_VOLATILE && !FULL_REGS(regs))
                        break;
        }
-       printk("\n");
+       pr_cont("\n");
 #ifdef CONFIG_KALLSYMS
        /*
         * Lookup NIP late so we have the best change of getting the
@@ -1900,14 +1900,14 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
                        printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip);
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
                        if ((ip == rth) && curr_frame >= 0) {
-                               printk(" (%pS)",
+                               pr_cont(" (%pS)",
                                       (void *)current->ret_stack[curr_frame].ret);
                                curr_frame--;
                        }
 #endif
                        if (firstframe)
-                               printk(" (unreliable)");
-                       printk("\n");
+                               pr_cont(" (unreliable)");
+                       pr_cont("\n");
                }
                firstframe = 0;
 
index f52b7db327c80a3b603fb2a7179a2f97d6a054be..010b7b310237e4be38ef1d7bcc15a76050fc4469 100644 (file)
@@ -74,7 +74,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        break;
 
                copied = access_process_vm(child, (u64)addrOthers, &tmp,
-                               sizeof(tmp), 0);
+                               sizeof(tmp), FOLL_FORCE);
                if (copied != sizeof(tmp))
                        break;
                ret = put_user(tmp, (u32 __user *)data);
@@ -179,7 +179,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        break;
                ret = 0;
                if (access_process_vm(child, (u64)addrOthers, &tmp,
-                                       sizeof(tmp), 1) == sizeof(tmp))
+                                       sizeof(tmp),
+                                       FOLL_FORCE | FOLL_WRITE) == sizeof(tmp))
                        break;
                ret = -EIO;
                break;
index 7ac8e6eaab5ba24566f1f6fe06829e22727e86ea..8d586cff8a41f7e95b9ec7fc44b7126a4904c9dc 100644 (file)
@@ -226,17 +226,25 @@ static void __init configure_exceptions(void)
                if (firmware_has_feature(FW_FEATURE_OPAL))
                        opal_configure_cores();
 
-               /* Enable AIL if supported, and we are in hypervisor mode */
-               if (early_cpu_has_feature(CPU_FTR_HVMODE) &&
-                   early_cpu_has_feature(CPU_FTR_ARCH_207S)) {
-                       unsigned long lpcr = mfspr(SPRN_LPCR);
-                       mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
-               }
+               /* AIL on native is done in cpu_ready_for_interrupts() */
        }
 }
 
 static void cpu_ready_for_interrupts(void)
 {
+       /*
+        * Enable AIL if supported, and we are in hypervisor mode. This
+        * is called once for every processor.
+        *
+        * If we are not in hypervisor mode the job is done once for
+        * the whole partition in configure_exceptions().
+        */
+       if (early_cpu_has_feature(CPU_FTR_HVMODE) &&
+           early_cpu_has_feature(CPU_FTR_ARCH_207S)) {
+               unsigned long lpcr = mfspr(SPRN_LPCR);
+               mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
+       }
+
        /* Set IR and DR in PACA MSR */
        get_paca()->kernel_msr = MSR_KERNEL;
 }
index 8295f51c1a5f9023022273d6e19b9e2a46ae4451..7394b770ae1f6b2402ef2b04fe23e92eae2c7ee2 100644 (file)
@@ -94,8 +94,17 @@ SECTIONS
         * detected, and will result in a crash at boot due to offsets being
         * wrong.
         */
+#ifdef CONFIG_PPC64
+       /*
+        * BLOCK(0) overrides the default output section alignment because
+        * this needs to start right after .head.text in order for fixed
+        * section placement to work.
+        */
+       .text BLOCK(0) : AT(ADDR(.text) - LOAD_OFFSET) {
+#else
        .text : AT(ADDR(.text) - LOAD_OFFSET) {
                ALIGN_FUNCTION();
+#endif
                /* careful! __ftr_alt_* sections need to be close to .text */
                *(.text .fixup __ftr_alt_* .ref.text)
                SCHED_TEXT
index 82ff5de8b1e7a5564df01dd323c0662ab6457b3b..a0ea63ac2b521b6f8a861aa4b211c0c08dd1062f 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/ppc-opcode.h>
 #include <asm/pnv-pci.h>
 #include <asm/opal.h>
+#include <asm/smp.h>
 
 #include "book3s_xics.h"
 
index bb0354222b1158c57133a09ef50b98cf20de6f29..362954f98029b46d4d3d312b239bb7a2fa8fe63a 100644 (file)
@@ -106,6 +106,8 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
        switch (REGION_ID(ea)) {
        case USER_REGION_ID:
                pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
+               if (mm == NULL)
+                       return 1;
                psize = get_slice_psize(mm, ea);
                ssize = user_segment_size(ea);
                vsid = get_vsid(mm->context.id, ea, ssize);
index 42c702b3be1ff795d36b2039ba0d0bcef01305c2..6fa450c12d6d1b28c71429ac4aa10fdd4dabf2a0 100644 (file)
@@ -55,7 +55,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
         */
        rflags = htab_convert_pte_flags(new_pte);
 
-       if (!cpu_has_feature(CPU_FTR_NOEXECUTE) &&
+       if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
            !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
                rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
 
index 3bbbea07378c60b56e545d74ebc6e17301f0644f..1a68cb19b0e33c0031a1568f9e977f1681b80cd8 100644 (file)
@@ -87,7 +87,7 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
        subpg_pte = new_pte & ~subpg_prot;
        rflags = htab_convert_pte_flags(subpg_pte);
 
-       if (!cpu_has_feature(CPU_FTR_NOEXECUTE) &&
+       if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
            !cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
 
                /*
@@ -258,7 +258,7 @@ int __hash_page_64K(unsigned long ea, unsigned long access,
 
        rflags = htab_convert_pte_flags(new_pte);
 
-       if (!cpu_has_feature(CPU_FTR_NOEXECUTE) &&
+       if (cpu_has_feature(CPU_FTR_NOEXECUTE) &&
            !cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
                rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
 
index 44d3c3a38e3ecc71c779b4a09f07e2c12261a99b..78dabf065ba96eb755267b9099e50dd6f024653d 100644 (file)
@@ -193,8 +193,12 @@ unsigned long htab_convert_pte_flags(unsigned long pteflags)
                /*
                 * Kernel read only mapped with ppp bits 0b110
                 */
-               if (!(pteflags & _PAGE_WRITE))
-                       rflags |= (HPTE_R_PP0 | 0x2);
+               if (!(pteflags & _PAGE_WRITE)) {
+                       if (mmu_has_feature(MMU_FTR_KERNEL_RO))
+                               rflags |= (HPTE_R_PP0 | 0x2);
+                       else
+                               rflags |= 0x3;
+               }
        } else {
                if (pteflags & _PAGE_RWX)
                        rflags |= 0x2;
@@ -1029,6 +1033,10 @@ void hash__early_init_mmu_secondary(void)
 {
        /* Initialize hash table for that CPU */
        if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+
+               if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+                       update_hid_for_hash();
+
                if (!cpu_has_feature(CPU_FTR_ARCH_300))
                        mtspr(SPRN_SDR1, _SDR1);
                else
index 75b9cd6150cc80c98aa4dfec8ab633f126638f01..a51c188b81f31bf1c3c5ecbe5f0b8dd572a65ccb 100644 (file)
@@ -845,7 +845,7 @@ void __init dump_numa_cpu_topology(void)
                return;
 
        for_each_online_node(node) {
-               printk(KERN_DEBUG "Node %d CPUs:", node);
+               pr_info("Node %d CPUs:", node);
 
                count = 0;
                /*
@@ -856,52 +856,18 @@ void __init dump_numa_cpu_topology(void)
                        if (cpumask_test_cpu(cpu,
                                        node_to_cpumask_map[node])) {
                                if (count == 0)
-                                       printk(" %u", cpu);
+                                       pr_cont(" %u", cpu);
                                ++count;
                        } else {
                                if (count > 1)
-                                       printk("-%u", cpu - 1);
+                                       pr_cont("-%u", cpu - 1);
                                count = 0;
                        }
                }
 
                if (count > 1)
-                       printk("-%u", nr_cpu_ids - 1);
-               printk("\n");
-       }
-}
-
-static void __init dump_numa_memory_topology(void)
-{
-       unsigned int node;
-       unsigned int count;
-
-       if (min_common_depth == -1 || !numa_enabled)
-               return;
-
-       for_each_online_node(node) {
-               unsigned long i;
-
-               printk(KERN_DEBUG "Node %d Memory:", node);
-
-               count = 0;
-
-               for (i = 0; i < memblock_end_of_DRAM();
-                    i += (1 << SECTION_SIZE_BITS)) {
-                       if (early_pfn_to_nid(i >> PAGE_SHIFT) == node) {
-                               if (count == 0)
-                                       printk(" 0x%lx", i);
-                               ++count;
-                       } else {
-                               if (count > 0)
-                                       printk("-0x%lx", i);
-                               count = 0;
-                       }
-               }
-
-               if (count > 0)
-                       printk("-0x%lx", i);
-               printk("\n");
+                       pr_cont("-%u", nr_cpu_ids - 1);
+               pr_cont("\n");
        }
 }
 
@@ -947,8 +913,6 @@ void __init initmem_init(void)
 
        if (parse_numa_properties())
                setup_nonnuma();
-       else
-               dump_numa_memory_topology();
 
        memblock_dump_all();
 
index ed7bddc456b72b5a7ce1b647438cd2271306302a..688b54517655f1ef787023f18f3cacdcbd62ba3b 100644 (file)
@@ -388,6 +388,10 @@ void radix__early_init_mmu_secondary(void)
         * update partition table control register and UPRT
         */
        if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+
+               if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+                       update_hid_for_radix();
+
                lpcr = mfspr(SPRN_LPCR);
                mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR);
 
index 0e49ec541ab57c91fbf568947cf02ac4f9bbe1ac..3493cf4e045258df20f5cf47990e991b6af265b7 100644 (file)
@@ -50,6 +50,8 @@ static inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
        for (set = 0; set < POWER9_TLB_SETS_RADIX ; set++) {
                __tlbiel_pid(pid, set, ric);
        }
+       if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+               asm volatile(PPC_INVALIDATE_ERAT : : :"memory");
        return;
 }
 
@@ -83,6 +85,8 @@ static inline void _tlbiel_va(unsigned long va, unsigned long pid,
        asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
                     : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
        asm volatile("ptesync": : :"memory");
+       if (cpu_has_feature(CPU_FTR_POWER9_DD1))
+               asm volatile(PPC_INVALIDATE_ERAT : : :"memory");
 }
 
 static inline void _tlbie_va(unsigned long va, unsigned long pid,
@@ -175,7 +179,7 @@ void radix__flush_tlb_mm(struct mm_struct *mm)
        if (unlikely(pid == MMU_NO_CONTEXT))
                goto no_context;
 
-       if (!mm_is_core_local(mm)) {
+       if (!mm_is_thread_local(mm)) {
                int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
 
                if (lock_tlbie)
@@ -201,7 +205,7 @@ void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr)
        if (unlikely(pid == MMU_NO_CONTEXT))
                goto no_context;
 
-       if (!mm_is_core_local(mm)) {
+       if (!mm_is_thread_local(mm)) {
                int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
 
                if (lock_tlbie)
@@ -226,7 +230,7 @@ void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
        pid = mm ? mm->context.id : 0;
        if (unlikely(pid == MMU_NO_CONTEXT))
                goto bail;
-       if (!mm_is_core_local(mm)) {
+       if (!mm_is_thread_local(mm)) {
                int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
 
                if (lock_tlbie)
@@ -321,7 +325,7 @@ void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start,
 {
        unsigned long pid;
        unsigned long addr;
-       int local = mm_is_core_local(mm);
+       int local = mm_is_thread_local(mm);
        unsigned long ap = mmu_get_ap(psize);
        int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
        unsigned long page_size = 1UL << mmu_psize_defs[psize].shift;
index 28f03ca60100a3399b501721851b789871c787e2..794bebb43d23d285370138d70bef7aab8a1e905a 100644 (file)
@@ -363,11 +363,11 @@ out:
 static int diag224_get_name_table(void)
 {
        /* memory must be below 2GB */
-       diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+       diag224_cpu_names = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
        if (!diag224_cpu_names)
                return -ENOMEM;
        if (diag224(diag224_cpu_names)) {
-               kfree(diag224_cpu_names);
+               free_page((unsigned long) diag224_cpu_names);
                return -EOPNOTSUPP;
        }
        EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
@@ -376,7 +376,7 @@ static int diag224_get_name_table(void)
 
 static void diag224_delete_name_table(void)
 {
-       kfree(diag224_cpu_names);
+       free_page((unsigned long) diag224_cpu_names);
 }
 
 static int diag224_idx2name(int index, char *name)
index 64053d9ac3f23b7cb1bf23aa42aa435b9f2ae0f8..836c56290499b84c0dad7785e9aa5979d68ed0bf 100644 (file)
@@ -12,9 +12,7 @@
 
 #ifndef __ASSEMBLY__
 
-unsigned long return_address(int depth);
-
-#define ftrace_return_address(n) return_address(n)
+#define ftrace_return_address(n) __builtin_return_address(n)
 
 void _mcount(void);
 void ftrace_caller(void);
index 03323175de308fbb3f98ecd5595f66f2d92e9580..602af692efdc1b5273e466b474dbf1a6c7e25922 100644 (file)
@@ -192,7 +192,7 @@ struct task_struct;
 struct mm_struct;
 struct seq_file;
 
-typedef int (*dump_trace_func_t)(void *data, unsigned long address);
+typedef int (*dump_trace_func_t)(void *data, unsigned long address, int reliable);
 void dump_trace(dump_trace_func_t func, void *data,
                struct task_struct *task, unsigned long sp);
 
index 02613bad8bbba4cc4a6e2de3dcc07846946536bf..3066031a73feeeecde2a3ae6f9c5913bf9f8c7d6 100644 (file)
@@ -9,6 +9,9 @@
 #include <uapi/asm/unistd.h>
 
 #define __IGNORE_time
+#define __IGNORE_pkey_mprotect
+#define __IGNORE_pkey_alloc
+#define __IGNORE_pkey_free
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_ALARM
index 43446fa2a4e55cdc49b7f89d639483f1ed738164..c74c59236f4418c3f37933ff67b4812c101e8536 100644 (file)
@@ -2014,12 +2014,12 @@ void show_code(struct pt_regs *regs)
                        *ptr++ = '\t';
                ptr += print_insn(ptr, code + start, addr);
                start += opsize;
-               printk("%s", buffer);
+               pr_cont("%s", buffer);
                ptr = buffer;
                ptr += sprintf(ptr, "\n          ");
                hops++;
        }
-       printk("\n");
+       pr_cont("\n");
 }
 
 void print_fn_code(unsigned char *code, unsigned long len)
index 6693383bc01bc7b78b4a98895a06052ccd8d77ec..55d4fe174fd9728a880016dcf14c7e281ffcdc4f 100644 (file)
@@ -38,10 +38,10 @@ __dump_trace(dump_trace_func_t func, void *data, unsigned long sp,
                if (sp < low || sp > high - sizeof(*sf))
                        return sp;
                sf = (struct stack_frame *) sp;
+               if (func(data, sf->gprs[8], 0))
+                       return sp;
                /* Follow the backchain. */
                while (1) {
-                       if (func(data, sf->gprs[8]))
-                               return sp;
                        low = sp;
                        sp = sf->back_chain;
                        if (!sp)
@@ -49,6 +49,8 @@ __dump_trace(dump_trace_func_t func, void *data, unsigned long sp,
                        if (sp <= low || sp > high - sizeof(*sf))
                                return sp;
                        sf = (struct stack_frame *) sp;
+                       if (func(data, sf->gprs[8], 1))
+                               return sp;
                }
                /* Zero backchain detected, check for interrupt frame. */
                sp = (unsigned long) (sf + 1);
@@ -56,7 +58,7 @@ __dump_trace(dump_trace_func_t func, void *data, unsigned long sp,
                        return sp;
                regs = (struct pt_regs *) sp;
                if (!user_mode(regs)) {
-                       if (func(data, regs->psw.addr))
+                       if (func(data, regs->psw.addr, 1))
                                return sp;
                }
                low = sp;
@@ -85,33 +87,12 @@ void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task,
 }
 EXPORT_SYMBOL_GPL(dump_trace);
 
-struct return_address_data {
-       unsigned long address;
-       int depth;
-};
-
-static int __return_address(void *data, unsigned long address)
-{
-       struct return_address_data *rd = data;
-
-       if (rd->depth--)
-               return 0;
-       rd->address = address;
-       return 1;
-}
-
-unsigned long return_address(int depth)
-{
-       struct return_address_data rd = { .depth = depth + 2 };
-
-       dump_trace(__return_address, &rd, NULL, current_stack_pointer());
-       return rd.address;
-}
-EXPORT_SYMBOL_GPL(return_address);
-
-static int show_address(void *data, unsigned long address)
+static int show_address(void *data, unsigned long address, int reliable)
 {
-       printk("([<%016lx>] %pSR)\n", address, (void *)address);
+       if (reliable)
+               printk(" [<%016lx>] %pSR \n", address, (void *)address);
+       else
+               printk("([<%016lx>] %pSR)\n", address, (void *)address);
        return 0;
 }
 
@@ -138,14 +119,14 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                else
                        stack = (unsigned long *)task->thread.ksp;
        }
+       printk(KERN_DEFAULT "Stack:\n");
        for (i = 0; i < 20; i++) {
                if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
                        break;
-               if ((i * sizeof(long) % 32) == 0)
-                       printk("%s       ", i == 0 ? "" : "\n");
-               printk("%016lx ", *stack++);
+               if (i % 4 == 0)
+                       printk(KERN_DEFAULT "       ");
+               pr_cont("%016lx%c", *stack++, i % 4 == 3 ? '\n' : ' ');
        }
-       printk("\n");
        show_trace(task, (unsigned long)sp);
 }
 
@@ -163,13 +144,13 @@ void show_registers(struct pt_regs *regs)
        mode = user_mode(regs) ? "User" : "Krnl";
        printk("%s PSW : %p %p", mode, (void *)regs->psw.mask, (void *)regs->psw.addr);
        if (!user_mode(regs))
-               printk(" (%pSR)", (void *)regs->psw.addr);
-       printk("\n");
+               pr_cont(" (%pSR)", (void *)regs->psw.addr);
+       pr_cont("\n");
        printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
               "P:%x AS:%x CC:%x PM:%x", psw->r, psw->t, psw->i, psw->e,
               psw->key, psw->m, psw->w, psw->p, psw->as, psw->cc, psw->pm);
-       printk(" RI:%x EA:%x", psw->ri, psw->eaba);
-       printk("\n%s GPRS: %016lx %016lx %016lx %016lx\n", mode,
+       pr_cont(" RI:%x EA:%x\n", psw->ri, psw->eaba);
+       printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode,
               regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
        printk("           %016lx %016lx %016lx %016lx\n",
               regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
@@ -205,14 +186,14 @@ void die(struct pt_regs *regs, const char *str)
        printk("%s: %04x ilc:%d [#%d] ", str, regs->int_code & 0xffff,
               regs->int_code >> 17, ++die_counter);
 #ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
+       pr_cont("PREEMPT ");
 #endif
 #ifdef CONFIG_SMP
-       printk("SMP ");
+       pr_cont("SMP ");
 #endif
        if (debug_pagealloc_enabled())
-               printk("DEBUG_PAGEALLOC");
-       printk("\n");
+               pr_cont("DEBUG_PAGEALLOC");
+       pr_cont("\n");
        notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
        print_modules();
        show_regs(regs);
index 17431f63de00279bbef1b1619ce3966f395c7e74..955a7b6fa0a453bacf588de42e80a95e07ade61a 100644 (file)
@@ -222,7 +222,7 @@ static int __init service_level_perf_register(void)
 }
 arch_initcall(service_level_perf_register);
 
-static int __perf_callchain_kernel(void *data, unsigned long address)
+static int __perf_callchain_kernel(void *data, unsigned long address, int reliable)
 {
        struct perf_callchain_entry_ctx *entry = data;
 
index 44f84b23d4e5996f1ddc594ae3985d762e80aa36..355db9db82104d11bac97f7c23c59fa363859757 100644 (file)
@@ -27,12 +27,12 @@ static int __save_address(void *data, unsigned long address, int nosched)
        return 1;
 }
 
-static int save_address(void *data, unsigned long address)
+static int save_address(void *data, unsigned long address, int reliable)
 {
        return __save_address(data, address, 0);
 }
 
-static int save_address_nosched(void *data, unsigned long address)
+static int save_address_nosched(void *data, unsigned long address, int reliable)
 {
        return __save_address(data, address, 1);
 }
index 000e6e91f6a0630c53f35519d450fccf02479e55..3667d20e997f3ccac943438ad2e03588795afb33 100644 (file)
@@ -62,9 +62,11 @@ SECTIONS
 
        . = ALIGN(PAGE_SIZE);
        __start_ro_after_init = .;
+       __start_data_ro_after_init = .;
        .data..ro_after_init : {
                 *(.data..ro_after_init)
        }
+       __end_data_ro_after_init = .;
        EXCEPTION_TABLE(16)
        . = ALIGN(PAGE_SIZE);
        __end_ro_after_init = .;
index 1cab8a177d0e7b7c80e1556e659c4751b0657187..7a27eebab28ad023069d21ae92033a06f4ab482d 100644 (file)
@@ -119,8 +119,13 @@ static int handle_validity(struct kvm_vcpu *vcpu)
 
        vcpu->stat.exit_validity++;
        trace_kvm_s390_intercept_validity(vcpu, viwhy);
-       WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy);
-       return -EOPNOTSUPP;
+       KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy,
+                 current->pid, vcpu->kvm);
+
+       /* do not warn on invalid runtime instrumentation mode */
+       WARN_ONCE(viwhy != 0x44, "kvm: unhandled validity intercept 0x%x\n",
+                 viwhy);
+       return -EINVAL;
 }
 
 static int handle_instruction(struct kvm_vcpu *vcpu)
index bd98b7d252004dae3d9ea569c6705ea92c8e51f0..05c98bb853cf971117530967a94f9176f85ef049 100644 (file)
@@ -315,7 +315,7 @@ static void fill_diag(struct sthyi_sctns *sctns)
        if (r < 0)
                goto out;
 
-       diag224_buf = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+       diag224_buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
        if (!diag224_buf || diag224(diag224_buf))
                goto out;
 
@@ -378,7 +378,7 @@ static void fill_diag(struct sthyi_sctns *sctns)
        sctns->par.infpval1 |= PAR_WGHT_VLD;
 
 out:
-       kfree(diag224_buf);
+       free_page((unsigned long)diag224_buf);
        vfree(diag204_buf);
 }
 
index adb0c34bf431e121d66caff904c30fb7e63e933d..18d4107e10eefb5e2ea5935412a95e7a03f2ae41 100644 (file)
@@ -266,7 +266,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
        /* Try to get the remaining pages with get_user_pages */
        start += nr << PAGE_SHIFT;
        pages += nr;
-       ret = get_user_pages_unlocked(start, nr_pages - nr, write, 0, pages);
+       ret = get_user_pages_unlocked(start, nr_pages - nr, pages,
+                                     write ? FOLL_WRITE : 0);
        /* Have to be a bit careful with return values */
        if (nr > 0)
                ret = (ret < 0) ? nr : ret + nr;
index cd404aa3931c101c963f9940e80669173453022c..4a0c5bce3552b00ba4863622fcc63de7b711614c 100644 (file)
@@ -217,6 +217,7 @@ static __init int setup_hugepagesz(char *opt)
        } else if (MACHINE_HAS_EDAT2 && size == PUD_SIZE) {
                hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
        } else {
+               hugetlb_bad_size();
                pr_err("hugepagesz= specifies an unsupported page size %s\n",
                        string);
                return 0;
index f56a39bd8ba688afbc29832b63305fa32b3e725d..b3e9d18f2ec62b603737ef5d0080cd86b8df94a8 100644 (file)
@@ -151,36 +151,40 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
 #ifdef CONFIG_MEMORY_HOTPLUG
 int arch_add_memory(int nid, u64 start, u64 size, bool for_device)
 {
-       unsigned long normal_end_pfn = PFN_DOWN(memblock_end_of_DRAM());
-       unsigned long dma_end_pfn = PFN_DOWN(MAX_DMA_ADDRESS);
+       unsigned long zone_start_pfn, zone_end_pfn, nr_pages;
        unsigned long start_pfn = PFN_DOWN(start);
        unsigned long size_pages = PFN_DOWN(size);
-       unsigned long nr_pages;
-       int rc, zone_enum;
+       pg_data_t *pgdat = NODE_DATA(nid);
+       struct zone *zone;
+       int rc, i;
 
        rc = vmem_add_mapping(start, size);
        if (rc)
                return rc;
 
-       while (size_pages > 0) {
-               if (start_pfn < dma_end_pfn) {
-                       nr_pages = (start_pfn + size_pages > dma_end_pfn) ?
-                                  dma_end_pfn - start_pfn : size_pages;
-                       zone_enum = ZONE_DMA;
-               } else if (start_pfn < normal_end_pfn) {
-                       nr_pages = (start_pfn + size_pages > normal_end_pfn) ?
-                                  normal_end_pfn - start_pfn : size_pages;
-                       zone_enum = ZONE_NORMAL;
+       for (i = 0; i < MAX_NR_ZONES; i++) {
+               zone = pgdat->node_zones + i;
+               if (zone_idx(zone) != ZONE_MOVABLE) {
+                       /* Add range within existing zone limits, if possible */
+                       zone_start_pfn = zone->zone_start_pfn;
+                       zone_end_pfn = zone->zone_start_pfn +
+                                      zone->spanned_pages;
                } else {
-                       nr_pages = size_pages;
-                       zone_enum = ZONE_MOVABLE;
+                       /* Add remaining range to ZONE_MOVABLE */
+                       zone_start_pfn = start_pfn;
+                       zone_end_pfn = start_pfn + size_pages;
                }
-               rc = __add_pages(nid, NODE_DATA(nid)->node_zones + zone_enum,
-                                start_pfn, size_pages);
+               if (start_pfn < zone_start_pfn || start_pfn >= zone_end_pfn)
+                       continue;
+               nr_pages = (start_pfn + size_pages > zone_end_pfn) ?
+                          zone_end_pfn - start_pfn : size_pages;
+               rc = __add_pages(nid, zone, start_pfn, nr_pages);
                if (rc)
                        break;
                start_pfn += nr_pages;
                size_pages -= nr_pages;
+               if (!size_pages)
+                       break;
        }
        if (rc)
                vmem_remove_mapping(start, size);
index 16f4c3960b874b2dc2129926c45c8343a3f7403c..9a4de4599c7b99a82f4a38989a309c896f4e73f3 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/init.h>
 #include <asm/processor.h>
 
-static int __s390_backtrace(void *data, unsigned long address)
+static int __s390_backtrace(void *data, unsigned long address, int reliable)
 {
        unsigned int *depth = data;
 
index 7350c8bc13a290ca362ad25b69cdb050c72ab3f4..6b2f72f523b91bb6c68347602b33ca2446807229 100644 (file)
@@ -423,7 +423,7 @@ static int __s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
        dma_addr_t dma_addr_base, dma_addr;
        int flags = ZPCI_PTE_VALID;
        struct scatterlist *s;
-       unsigned long pa;
+       unsigned long pa = 0;
        int ret;
 
        size = PAGE_ALIGN(size);
index 55836188b217c170c3141558d843e1d4259bf165..4f7314d5f3347d40a6282976d538ccfb0e4d447d 100644 (file)
@@ -131,7 +131,7 @@ read_tsk_long(struct task_struct *child,
 {
        int copied;
 
-       copied = access_process_vm(child, addr, res, sizeof(*res), 0);
+       copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE);
 
        return copied != sizeof(*res) ? -EIO : 0;
 }
@@ -142,7 +142,7 @@ read_tsk_short(struct task_struct *child,
 {
        int copied;
 
-       copied = access_process_vm(child, addr, res, sizeof(*res), 0);
+       copied = access_process_vm(child, addr, res, sizeof(*res), FOLL_FORCE);
 
        return copied != sizeof(*res) ? -EIO : 0;
 }
@@ -153,7 +153,8 @@ write_tsk_short(struct task_struct *child,
 {
        int copied;
 
-       copied = access_process_vm(child, addr, &val, sizeof(val), 1);
+       copied = access_process_vm(child, addr, &val, sizeof(val),
+                       FOLL_FORCE | FOLL_WRITE);
 
        return copied != sizeof(val) ? -EIO : 0;
 }
@@ -164,7 +165,8 @@ write_tsk_long(struct task_struct *child,
 {
        int copied;
 
-       copied = access_process_vm(child, addr, &val, sizeof(val), 1);
+       copied = access_process_vm(child, addr, &val, sizeof(val),
+                       FOLL_FORCE | FOLL_WRITE);
 
        return copied != sizeof(val) ? -EIO : 0;
 }
index 00476662ac2c07ba1e0a3bb427e114ae2f5a7650..336f33a419d99561d57b329a3ee6a513164ca43f 100644 (file)
@@ -31,7 +31,7 @@ isa-y                                 := $(isa-y)-up
 endif
 
 cflags-$(CONFIG_CPU_SH2)               := $(call cc-option,-m2,)
-cflags-$(CONFIG_CPU_J2)                        := $(call cc-option,-mj2,)
+cflags-$(CONFIG_CPU_J2)                        += $(call cc-option,-mj2,)
 cflags-$(CONFIG_CPU_SH2A)              += $(call cc-option,-m2a,) \
                                           $(call cc-option,-m2a-nofpu,) \
                                           $(call cc-option,-m4-nofpu,)
index e9c2c42031fee497379af3e3fff29d519275eaee..4e21949593cf59f20c4290285d7c4c28db7acc30 100644 (file)
@@ -22,6 +22,16 @@ config SH_DEVICE_TREE
          have sufficient driver coverage to use this option; do not
          select it if you are using original SuperH hardware.
 
+config SH_JCORE_SOC
+       bool "J-Core SoC"
+       depends on SH_DEVICE_TREE && (CPU_SH2 || CPU_J2)
+       select CLKSRC_JCORE_PIT
+       select JCORE_AIC
+       default y if CPU_J2
+       help
+         Select this option to include drivers core components of the
+         J-Core SoC, including interrupt controllers and timers.
+
 config SH_SOLUTION_ENGINE
        bool "SolutionEngine"
        select SOLUTION_ENGINE
index 94d1eca52f723e82df0792c96d87783c6a422245..2eb81ebe3888bf8a4bdd2af4b575c0e254f52f02 100644 (file)
@@ -8,6 +8,7 @@ CONFIG_MEMORY_START=0x10000000
 CONFIG_MEMORY_SIZE=0x04000000
 CONFIG_CPU_BIG_ENDIAN=y
 CONFIG_SH_DEVICE_TREE=y
+CONFIG_SH_JCORE_SOC=y
 CONFIG_HZ_100=y
 CONFIG_CMDLINE_OVERWRITE=y
 CONFIG_CMDLINE="console=ttyUL0 earlycon"
@@ -20,6 +21,7 @@ CONFIG_INET=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_NETDEVICES=y
+CONFIG_SERIAL_EARLYCON=y
 CONFIG_SERIAL_UARTLITE=y
 CONFIG_SERIAL_UARTLITE_CONSOLE=y
 CONFIG_I2C=y
index 40fa6c8adc43a361c60ffee8929aa39d2449e926..063c298ba56cc900479eb9b50a8c9587678f6893 100644 (file)
@@ -258,7 +258,8 @@ slow_irqon:
                pages += nr;
 
                ret = get_user_pages_unlocked(start,
-                       (end - start) >> PAGE_SHIFT, write, 0, pages);
+                       (end - start) >> PAGE_SHIFT, pages,
+                       write ? FOLL_WRITE : 0);
 
                /* Have to be a bit careful with return values */
                if (nr > 0) {
index b23c76b42d6e8c1508c04e3dbb65b05b24bce7c3..165ecdd24d22dec52108d54d2b31db4a38f55aab 100644 (file)
@@ -43,6 +43,7 @@ config SPARC
        select ARCH_HAS_SG_CHAIN
        select CPU_NO_EFFICIENT_FFS
        select HAVE_ARCH_HARDENED_USERCOPY
+       select PROVE_LOCKING_SMALL if PROVE_LOCKING
 
 config SPARC32
        def_bool !64BIT
@@ -89,6 +90,14 @@ config ARCH_DEFCONFIG
 config ARCH_PROC_KCORE_TEXT
        def_bool y
 
+config ARCH_ATU
+       bool
+       default y if SPARC64
+
+config ARCH_DMA_ADDR_T_64BIT
+       bool
+       default y if ARCH_ATU
+
 config IOMMU_HELPER
        bool
        default y if SPARC64
@@ -304,6 +313,20 @@ config ARCH_SPARSEMEM_ENABLE
 config ARCH_SPARSEMEM_DEFAULT
        def_bool y if SPARC64
 
+config FORCE_MAX_ZONEORDER
+       int "Maximum zone order"
+       default "13"
+       help
+         The kernel memory allocator divides physically contiguous memory
+         blocks into "zones", where each zone is a power of two number of
+         pages.  This option selects the largest power of two that the kernel
+         keeps in the memory allocator.  If you need to allocate very large
+         blocks of physically contiguous memory, then you may need to
+         increase this value.
+
+         This config option is actually maximum order plus one. For example,
+         a value of 13 means that the largest free memory block is 2^12 pages.
+
 source "mm/Kconfig"
 
 if SPARC64
index a6cfdabb6054aef28846342f49fdb2718e1263a5..5b0ed48e5b0c2e8e201a4bc5abe1cedd02833a7d 100644 (file)
@@ -24,9 +24,10 @@ typedef struct {
        unsigned int    icache_line_size;
        unsigned int    ecache_size;
        unsigned int    ecache_line_size;
-       unsigned short  sock_id;
+       unsigned short  sock_id;        /* physical package */
        unsigned short  core_id;
-       int             proc_id;
+       unsigned short  max_cache_id;   /* groupings of highest shared cache */
+       unsigned short  proc_id;        /* strand (aka HW thread) id */
 } cpuinfo_sparc;
 
 DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
index 666d5ba230d2f83f0659000e85ade4f4c025f319..73cb8978df58c9f25e2f06101a84bf1101dc7cf3 100644 (file)
@@ -2335,6 +2335,348 @@ unsigned long sun4v_vintr_set_target(unsigned long dev_handle,
  */
 #define HV_FAST_PCI_MSG_SETVALID       0xd3
 
+/* PCI IOMMU v2 definitions and services
+ *
+ * While the PCI IO definitions above is valid IOMMU v2 adds new PCI IO
+ * definitions and services.
+ *
+ *     CTE             Clump Table Entry. First level table entry in the ATU.
+ *
+ *     pci_device_list
+ *                     A 32-bit aligned list of pci_devices.
+ *
+ *     pci_device_listp
+ *                     real address of a pci_device_list. 32-bit aligned.
+ *
+ *     iotte           IOMMU translation table entry.
+ *
+ *     iotte_attributes
+ *                     IO Attributes for IOMMU v2 mappings. In addition to
+ *                     read, write IOMMU v2 supports relax ordering
+ *
+ *     io_page_list    A 64-bit aligned list of real addresses. Each real
+ *                     address in an io_page_list must be properly aligned
+ *                     to the pagesize of the given IOTSB.
+ *
+ *     io_page_list_p  Real address of an io_page_list, 64-bit aligned.
+ *
+ *     IOTSB           IO Translation Storage Buffer. An aligned table of
+ *                     IOTTEs. Each IOTSB has a pagesize, table size, and
+ *                     virtual address associated with it that must match
+ *                     a pagesize and table size supported by the un-derlying
+ *                     hardware implementation. The alignment requirements
+ *                     for an IOTSB depend on the pagesize used for that IOTSB.
+ *                     Each IOTTE in an IOTSB maps one pagesize-sized page.
+ *                     The size of the IOTSB dictates how large of a virtual
+ *                     address space the IOTSB is capable of mapping.
+ *
+ *     iotsb_handle    An opaque identifier for an IOTSB. A devhandle plus
+ *                     iotsb_handle represents a binding of an IOTSB to a
+ *                     PCI root complex.
+ *
+ *     iotsb_index     Zero-based IOTTE number within an IOTSB.
+ */
+
+/* The index_count argument consists of two fields:
+ * bits 63:48 #iottes and bits 47:0 iotsb_index
+ */
+#define HV_PCI_IOTSB_INDEX_COUNT(__iottes, __iotsb_index) \
+       (((u64)(__iottes) << 48UL) | ((u64)(__iotsb_index)))
+
+/* pci_iotsb_conf()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_CONF
+ * ARG0:       devhandle
+ * ARG1:       r_addr
+ * ARG2:       size
+ * ARG3:       pagesize
+ * ARG4:       iova
+ * RET0:       status
+ * RET1:       iotsb_handle
+ * ERRORS:     EINVAL          Invalid devhandle, size, iova, or pagesize
+ *             EBADALIGN       r_addr is not properly aligned
+ *             ENORADDR        r_addr is not a valid real address
+ *             ETOOMANY        No further IOTSBs may be configured
+ *             EBUSY           Duplicate devhandle, raddir, iova combination
+ *
+ * Create an IOTSB suitable for the PCI root complex identified by devhandle,
+ * for the DMA virtual address defined by the argument iova.
+ *
+ * r_addr is the properly aligned base address of the IOTSB and size is the
+ * IOTSB (table) size in bytes.The IOTSB is required to be zeroed prior to
+ * being configured. If it contains any values other than zeros then the
+ * behavior is undefined.
+ *
+ * pagesize is the size of each page in the IOTSB. Note that the combination of
+ * size (table size) and pagesize must be valid.
+ *
+ * virt is the DMA virtual address this IOTSB will map.
+ *
+ * If successful, the opaque 64-bit handle iotsb_handle is returned in ret1.
+ * Once configured, privileged access to the IOTSB memory is prohibited and
+ * creates undefined behavior. The only permitted access is indirect via these
+ * services.
+ */
+#define HV_FAST_PCI_IOTSB_CONF         0x190
+
+/* pci_iotsb_info()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_INFO
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * RET0:       status
+ * RET1:       r_addr
+ * RET2:       size
+ * RET3:       pagesize
+ * RET4:       iova
+ * RET5:       #bound
+ * ERRORS:     EINVAL  Invalid devhandle or iotsb_handle
+ *
+ * This service returns configuration information about an IOTSB previously
+ * created with pci_iotsb_conf.
+ *
+ * iotsb_handle value 0 may be used with this service to inquire about the
+ * legacy IOTSB that may or may not exist. If the service succeeds, the return
+ * values describe the legacy IOTSB and I/O virtual addresses mapped by that
+ * table. However, the table base address r_addr may contain the value -1 which
+ * indicates a memory range that cannot be accessed or be reclaimed.
+ *
+ * The return value #bound contains the number of PCI devices that iotsb_handle
+ * is currently bound to.
+ */
+#define HV_FAST_PCI_IOTSB_INFO         0x191
+
+/* pci_iotsb_unconf()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_UNCONF
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * RET0:       status
+ * ERRORS:     EINVAL  Invalid devhandle or iotsb_handle
+ *             EBUSY   The IOTSB is bound and may not be unconfigured
+ *
+ * This service unconfigures the IOTSB identified by the devhandle and
+ * iotsb_handle arguments, previously created with pci_iotsb_conf.
+ * The IOTSB must not be currently bound to any device or the service will fail
+ *
+ * If the call succeeds, iotsb_handle is no longer valid.
+ */
+#define HV_FAST_PCI_IOTSB_UNCONF       0x192
+
+/* pci_iotsb_bind()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_BIND
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       pci_device
+ * RET0:       status
+ * ERRORS:     EINVAL  Invalid devhandle, iotsb_handle, or pci_device
+ *             EBUSY   A PCI function is already bound to an IOTSB at the same
+ *                     address range as specified by devhandle, iotsb_handle.
+ *
+ * This service binds the PCI function specified by the argument pci_device to
+ * the IOTSB specified by the arguments devhandle and iotsb_handle.
+ *
+ * The PCI device function is bound to the specified IOTSB with the IOVA range
+ * specified when the IOTSB was configured via pci_iotsb_conf. If the function
+ * is already bound then it is unbound first.
+ */
+#define HV_FAST_PCI_IOTSB_BIND         0x193
+
+/* pci_iotsb_unbind()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_UNBIND
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       pci_device
+ * RET0:       status
+ * ERRORS:     EINVAL  Invalid devhandle, iotsb_handle, or pci_device
+ *             ENOMAP  The PCI function was not bound to the specified IOTSB
+ *
+ * This service unbinds the PCI device specified by the argument pci_device
+ * from the IOTSB identified  * by the arguments devhandle and iotsb_handle.
+ *
+ * If the PCI device is not bound to the specified IOTSB then this service will
+ * fail with status ENOMAP
+ */
+#define HV_FAST_PCI_IOTSB_UNBIND       0x194
+
+/* pci_iotsb_get_binding()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_GET_BINDING
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       iova
+ * RET0:       status
+ * RET1:       iotsb_handle
+ * ERRORS:     EINVAL  Invalid devhandle, pci_device, or iova
+ *             ENOMAP  The PCI function is not bound to an IOTSB at iova
+ *
+ * This service returns the IOTSB binding, iotsb_handle, for a given pci_device
+ * and DMA virtual address, iova.
+ *
+ * iova must be the base address of a DMA virtual address range as defined by
+ * the iommu-address-ranges property in the root complex device node defined
+ * by the argument devhandle.
+ */
+#define HV_FAST_PCI_IOTSB_GET_BINDING  0x195
+
+/* pci_iotsb_map()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_MAP
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       index_count
+ * ARG3:       iotte_attributes
+ * ARG4:       io_page_list_p
+ * RET0:       status
+ * RET1:       #mapped
+ * ERRORS:     EINVAL          Invalid devhandle, iotsb_handle, #iottes,
+ *                             iotsb_index or iotte_attributes
+ *             EBADALIGN       Improperly aligned io_page_list_p or I/O page
+ *                             address in the I/O page list.
+ *             ENORADDR        Invalid io_page_list_p or I/O page address in
+ *                             the I/O page list.
+ *
+ * This service creates and flushes mappings in the IOTSB defined by the
+ * arguments devhandle, iotsb.
+ *
+ * The index_count argument consists of two fields. Bits 63:48 contain #iotte
+ * and bits 47:0 contain iotsb_index
+ *
+ * The first mapping is created in the IOTSB index specified by iotsb_index.
+ * Subsequent mappings are  created at iotsb_index+1 and so on.
+ *
+ * The attributes of each mapping are defined by the argument iotte_attributes.
+ *
+ * The io_page_list_p specifies the real address of the 64-bit-aligned list of
+ * #iottes I/O page addresses. Each page address must be a properly aligned
+ * real address of a page to be mapped in the IOTSB. The first entry in the I/O
+ * page list contains the real address of the first page, the 2nd entry for the
+ * 2nd page, and so on.
+ *
+ * #iottes must be greater than zero.
+ *
+ * The return value #mapped is the actual number of mappings created, which may
+ * be less than or equal to the argument #iottes. If the function returns
+ * successfully with a #mapped value less than the requested #iottes then the
+ * caller should continue to invoke the service with updated iotsb_index,
+ * #iottes, and io_page_list_p arguments until all pages are mapped.
+ *
+ * This service must not be used to demap a mapping. In other words, all
+ * mappings must be valid and have  one or both of the RW attribute bits set.
+ *
+ * Note:
+ * It is implementation-defined whether I/O page real address validity checking
+ * is done at time mappings are established or deferred until they are
+ * accessed.
+ */
+#define HV_FAST_PCI_IOTSB_MAP          0x196
+
+/* pci_iotsb_map_one()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_MAP_ONE
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       iotsb_index
+ * ARG3:       iotte_attributes
+ * ARG4:       r_addr
+ * RET0:       status
+ * ERRORS:     EINVAL          Invalid devhandle,iotsb_handle, iotsb_index
+ *                             or iotte_attributes
+ *             EBADALIGN       Improperly aligned r_addr
+ *             ENORADDR        Invalid r_addr
+ *
+ * This service creates and flushes a single mapping in the IOTSB defined by the
+ * arguments devhandle, iotsb.
+ *
+ * The mapping for the page at r_addr is created at the IOTSB index specified by
+ * iotsb_index with  the attributes iotte_attributes.
+ *
+ * This service must not be used to demap a mapping. In other words, the mapping
+ * must be valid and have one or both of the RW attribute bits set.
+ *
+ * Note:
+ * It is implementation-defined whether I/O page real address validity checking
+ * is done at time mappings are established or deferred until they are
+ * accessed.
+ */
+#define HV_FAST_PCI_IOTSB_MAP_ONE      0x197
+
+/* pci_iotsb_demap()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_DEMAP
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       iotsb_index
+ * ARG3:       #iottes
+ * RET0:       status
+ * RET1:       #unmapped
+ * ERRORS:     EINVAL  Invalid devhandle, iotsb_handle, iotsb_index or #iottes
+ *
+ * This service unmaps and flushes up to #iottes mappings starting at index
+ * iotsb_index from the IOTSB defined by the arguments devhandle, iotsb.
+ *
+ * #iottes must be greater than zero.
+ *
+ * The actual number of IOTTEs unmapped is returned in #unmapped and may be less
+ * than or equal to the requested number of IOTTEs, #iottes.
+ *
+ * If #unmapped is less than #iottes, the caller should continue to invoke this
+ * service with updated iotsb_index and #iottes arguments until all pages are
+ * demapped.
+ */
+#define HV_FAST_PCI_IOTSB_DEMAP                0x198
+
+/* pci_iotsb_getmap()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_GETMAP
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       iotsb_index
+ * RET0:       status
+ * RET1:       r_addr
+ * RET2:       iotte_attributes
+ * ERRORS:     EINVAL  Invalid devhandle, iotsb_handle, or iotsb_index
+ *             ENOMAP  No mapping was found
+ *
+ * This service returns the mapping specified by index iotsb_index from the
+ * IOTSB defined by the arguments devhandle, iotsb.
+ *
+ * Upon success, the real address of the mapping shall be returned in
+ * r_addr and thethe IOTTE mapping attributes shall be returned in
+ * iotte_attributes.
+ *
+ * The return value iotte_attributes may not include optional features used in
+ * the call to create the  mapping.
+ */
+#define HV_FAST_PCI_IOTSB_GETMAP       0x199
+
+/* pci_iotsb_sync_mappings()
+ * TRAP:       HV_FAST_TRAP
+ * FUNCTION:   HV_FAST_PCI_IOTSB_SYNC_MAPPINGS
+ * ARG0:       devhandle
+ * ARG1:       iotsb_handle
+ * ARG2:       iotsb_index
+ * ARG3:       #iottes
+ * RET0:       status
+ * RET1:       #synced
+ * ERROS:      EINVAL  Invalid devhandle, iotsb_handle, iotsb_index, or #iottes
+ *
+ * This service synchronizes #iottes mappings starting at index iotsb_index in
+ * the IOTSB defined by the arguments devhandle, iotsb.
+ *
+ * #iottes must be greater than zero.
+ *
+ * The actual number of IOTTEs synchronized is returned in #synced, which may
+ * be less than or equal to the requested number, #iottes.
+ *
+ * Upon a successful return, #synced is less than #iottes, the caller should
+ * continue to invoke this service with updated iotsb_index and #iottes
+ * arguments until all pages are synchronized.
+ */
+#define HV_FAST_PCI_IOTSB_SYNC_MAPPINGS        0x19a
+
 /* Logical Domain Channel services.  */
 
 #define LDC_CHANNEL_DOWN               0
@@ -2993,6 +3335,7 @@ unsigned long sun4v_m7_set_perfreg(unsigned long reg_num,
 #define HV_GRP_SDIO                    0x0108
 #define HV_GRP_SDIO_ERR                        0x0109
 #define HV_GRP_REBOOT_DATA             0x0110
+#define HV_GRP_ATU                     0x0111
 #define HV_GRP_M7_PERF                 0x0114
 #define HV_GRP_NIAG_PERF               0x0200
 #define HV_GRP_FIRE_PERF               0x0201
index cd0d69fa7592e64d6ac564eafac8ee622ea7ccfc..f24f356f250376e0931a4d4bc5d6bc631f469a74 100644 (file)
@@ -24,8 +24,36 @@ struct iommu_arena {
        unsigned int    limit;
 };
 
+#define ATU_64_SPACE_SIZE 0x800000000 /* 32G */
+
+/* Data structures for SPARC ATU architecture */
+struct atu_iotsb {
+       void    *table;         /* IOTSB table base virtual addr*/
+       u64     ra;             /* IOTSB table real addr */
+       u64     dvma_size;      /* ranges[3].size or OS slected 32G size */
+       u64     dvma_base;      /* ranges[3].base */
+       u64     table_size;     /* IOTSB table size */
+       u64     page_size;      /* IO PAGE size for IOTSB */
+       u32     iotsb_num;      /* tsbnum is same as iotsb_handle */
+};
+
+struct atu_ranges {
+       u64     base;
+       u64     size;
+};
+
+struct atu {
+       struct  atu_ranges      *ranges;
+       struct  atu_iotsb       *iotsb;
+       struct  iommu_map_table tbl;
+       u64                     base;
+       u64                     size;
+       u64                     dma_addr_mask;
+};
+
 struct iommu {
        struct iommu_map_table  tbl;
+       struct atu              *atu;
        spinlock_t              lock;
        u32                     dma_addr_mask;
        iopte_t                 *page_table;
index d9c5876c61215494df0238992da09c03f5d82211..8011e79f59c96f3658e430765e6aa56caa400098 100644 (file)
@@ -134,7 +134,7 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
        *(volatile __u32 *)&lp->lock = ~0U;
 }
 
-static void inline arch_write_unlock(arch_rwlock_t *lock)
+static inline void arch_write_unlock(arch_rwlock_t *lock)
 {
        __asm__ __volatile__(
 "      st              %%g0, [%0]"
index 87990b7c6b0d693eb4c715f33047e5d8cfa0e5c6..07c9f2e9bf57716eccabe5d55208dbc016b41881 100644 (file)
@@ -96,7 +96,7 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long fla
 
 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
 
-static void inline arch_read_lock(arch_rwlock_t *lock)
+static inline void arch_read_lock(arch_rwlock_t *lock)
 {
        unsigned long tmp1, tmp2;
 
@@ -119,7 +119,7 @@ static void inline arch_read_lock(arch_rwlock_t *lock)
        : "memory");
 }
 
-static int inline arch_read_trylock(arch_rwlock_t *lock)
+static inline int arch_read_trylock(arch_rwlock_t *lock)
 {
        int tmp1, tmp2;
 
@@ -140,7 +140,7 @@ static int inline arch_read_trylock(arch_rwlock_t *lock)
        return tmp1;
 }
 
-static void inline arch_read_unlock(arch_rwlock_t *lock)
+static inline void arch_read_unlock(arch_rwlock_t *lock)
 {
        unsigned long tmp1, tmp2;
 
@@ -156,7 +156,7 @@ static void inline arch_read_unlock(arch_rwlock_t *lock)
        : "memory");
 }
 
-static void inline arch_write_lock(arch_rwlock_t *lock)
+static inline void arch_write_lock(arch_rwlock_t *lock)
 {
        unsigned long mask, tmp1, tmp2;
 
@@ -181,7 +181,7 @@ static void inline arch_write_lock(arch_rwlock_t *lock)
        : "memory");
 }
 
-static void inline arch_write_unlock(arch_rwlock_t *lock)
+static inline void arch_write_unlock(arch_rwlock_t *lock)
 {
        __asm__ __volatile__(
 "      stw             %%g0, [%0]"
@@ -190,7 +190,7 @@ static void inline arch_write_unlock(arch_rwlock_t *lock)
        : "memory");
 }
 
-static int inline arch_write_trylock(arch_rwlock_t *lock)
+static inline int arch_write_trylock(arch_rwlock_t *lock)
 {
        unsigned long mask, tmp1, tmp2, result;
 
index bec481aaca1635999f8889a52c4dde68bc109014..7b4898a36eee8e09c125e3619188b9ba5916c6d4 100644 (file)
@@ -44,14 +44,20 @@ int __node_distance(int, int);
 #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_sib_map[cpu])
+#define topology_core_cache_cpumask(cpu)       (&cpu_core_sib_cache_map[cpu])
 #define topology_sibling_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];
+extern cpumask_t cpu_core_sib_cache_map[NR_CPUS];
+
+/**
+ * Return cores that shares the last level cache.
+ */
 static inline const struct cpumask *cpu_coregroup_mask(int cpu)
 {
-        return &cpu_core_map[cpu];
+       return &cpu_core_sib_cache_map[cpu];
 }
 
 #endif /* _ASM_SPARC64_TOPOLOGY_H */
index b68acc563235cc4a4fbffc197ab9e2d107aaae11..5373136c412bf33814c9721c95f0a6738ee45ddf 100644 (file)
@@ -82,7 +82,6 @@ static inline int access_ok(int type, const void __user * addr, unsigned long si
        return 1;
 }
 
-void __ret_efault(void);
 void __retl_efault(void);
 
 /* Uh, these should become the main single-value transfer routines..
@@ -189,55 +188,34 @@ int __get_user_bad(void);
 unsigned long __must_check ___copy_from_user(void *to,
                                             const void __user *from,
                                             unsigned long size);
-unsigned long copy_from_user_fixup(void *to, const void __user *from,
-                                  unsigned long size);
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long size)
 {
-       unsigned long ret;
-
        check_object_size(to, size, false);
 
-       ret = ___copy_from_user(to, from, size);
-       if (unlikely(ret))
-               ret = copy_from_user_fixup(to, from, size);
-
-       return ret;
+       return ___copy_from_user(to, from, size);
 }
 #define __copy_from_user copy_from_user
 
 unsigned long __must_check ___copy_to_user(void __user *to,
                                           const void *from,
                                           unsigned long size);
-unsigned long copy_to_user_fixup(void __user *to, const void *from,
-                                unsigned long size);
 static inline unsigned long __must_check
 copy_to_user(void __user *to, const void *from, unsigned long size)
 {
-       unsigned long ret;
-
        check_object_size(from, size, true);
 
-       ret = ___copy_to_user(to, from, size);
-       if (unlikely(ret))
-               ret = copy_to_user_fixup(to, from, size);
-       return ret;
+       return ___copy_to_user(to, from, size);
 }
 #define __copy_to_user copy_to_user
 
 unsigned long __must_check ___copy_in_user(void __user *to,
                                           const void __user *from,
                                           unsigned long size);
-unsigned long copy_in_user_fixup(void __user *to, void __user *from,
-                                unsigned long size);
 static inline unsigned long __must_check
 copy_in_user(void __user *to, void __user *from, unsigned long size)
 {
-       unsigned long ret = ___copy_in_user(to, from, size);
-
-       if (unlikely(ret))
-               ret = copy_in_user_fixup(to, from, size);
-       return ret;
+       return ___copy_in_user(to, from, size);
 }
 #define __copy_in_user copy_in_user
 
index beba6c11554cb835517f911893819fffd0d8ad9e..6aa3da152c20008a08e752c4f9708ff6a89e3d72 100644 (file)
@@ -926,48 +926,11 @@ tlb_type: .word   0       /* Must NOT end up in BSS */
 EXPORT_SYMBOL(tlb_type)
        .section        ".fixup",#alloc,#execinstr
 
-       .globl  __ret_efault, __retl_efault, __ret_one, __retl_one
-ENTRY(__ret_efault)
-       ret
-        restore %g0, -EFAULT, %o0
-ENDPROC(__ret_efault)
-EXPORT_SYMBOL(__ret_efault)
-
 ENTRY(__retl_efault)
        retl
         mov    -EFAULT, %o0
 ENDPROC(__retl_efault)
 
-ENTRY(__retl_one)
-       retl
-        mov    1, %o0
-ENDPROC(__retl_one)
-
-ENTRY(__retl_one_fp)
-       VISExitHalf
-       retl
-        mov    1, %o0
-ENDPROC(__retl_one_fp)
-
-ENTRY(__ret_one_asi)
-       wr      %g0, ASI_AIUS, %asi
-       ret
-        restore %g0, 1, %o0
-ENDPROC(__ret_one_asi)
-
-ENTRY(__retl_one_asi)
-       wr      %g0, ASI_AIUS, %asi
-       retl
-        mov    1, %o0
-ENDPROC(__retl_one_asi)
-
-ENTRY(__retl_one_asi_fp)
-       wr      %g0, ASI_AIUS, %asi
-       VISExitHalf
-       retl
-        mov    1, %o0
-ENDPROC(__retl_one_asi_fp)
-
 ENTRY(__retl_o1)
        retl
         mov    %o1, %o0
index 662500fa555f74160f6449143e6d0785af2643e9..267731234ce8a2ee2cdc03686377c11a2ea6205f 100644 (file)
@@ -39,6 +39,7 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_SDIO,                                 },
        { .group = HV_GRP_SDIO_ERR,                             },
        { .group = HV_GRP_REBOOT_DATA,                          },
+       { .group = HV_GRP_ATU,          .flags = FLAG_PRE_API   },
        { .group = HV_GRP_NIAG_PERF,    .flags = FLAG_PRE_API   },
        { .group = HV_GRP_FIRE_PERF,                            },
        { .group = HV_GRP_N2_CPU,                               },
index 5c615abff030fdb6c26a7c68c86d5c3fa0544b94..852a3291db968986a0f77d240ccf7b58c3f9070a 100644 (file)
@@ -760,8 +760,12 @@ int dma_supported(struct device *dev, u64 device_mask)
        struct iommu *iommu = dev->archdata.iommu;
        u64 dma_addr_mask = iommu->dma_addr_mask;
 
-       if (device_mask >= (1UL << 32UL))
-               return 0;
+       if (device_mask > DMA_BIT_MASK(32)) {
+               if (iommu->atu)
+                       dma_addr_mask = iommu->atu->dma_addr_mask;
+               else
+                       return 0;
+       }
 
        if ((device_mask & dma_addr_mask) == dma_addr_mask)
                return 1;
index b40cec25290503b72dbf1d8c18e8f374ab51b44e..828493329f68d05e7ab1c47d6449a9f76adedddd 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/scatterlist.h>
 #include <linux/device.h>
 #include <linux/iommu-helper.h>
-#include <linux/scatterlist.h>
 
 #include <asm/iommu.h>
 
index 59bbeff550243dc10ea558a013d09825303e4793..07933b9e9ce00a34fc3677ee614a24ce2c0532a5 100644 (file)
 void arch_jump_label_transform(struct jump_entry *entry,
                               enum jump_label_type type)
 {
-       u32 val;
        u32 *insn = (u32 *) (unsigned long) entry->code;
+       u32 val;
 
        if (type == JUMP_LABEL_JMP) {
                s32 off = (s32)entry->target - (s32)entry->code;
+               bool use_v9_branch = false;
+
+               BUG_ON(off & 3);
 
 #ifdef CONFIG_SPARC64
-               /* ba,pt %xcc, . + (off << 2) */
-               val = 0x10680000 | ((u32) off >> 2);
-#else
-               /* ba . + (off << 2) */
-               val = 0x10800000 | ((u32) off >> 2);
+               if (off <= 0xfffff && off >= -0x100000)
+                       use_v9_branch = true;
 #endif
+               if (use_v9_branch) {
+                       /* WDISP19 - target is . + immed << 2 */
+                       /* ba,pt %xcc, . + off */
+                       val = 0x10680000 | (((u32) off >> 2) & 0x7ffff);
+               } else {
+                       /* WDISP22 - target is . + immed << 2 */
+                       BUG_ON(off > 0x7fffff);
+                       BUG_ON(off < -0x800000);
+                       /* ba . + off */
+                       val = 0x10800000 | (((u32) off >> 2) & 0x3fffff);
+               }
        } else {
                val = 0x01000000;
        }
index 11228861d9b4716dde53881c4b2184538dec6197..8a6982dfd7334fe1ff41cd830bbe320f05e25b30 100644 (file)
@@ -645,13 +645,20 @@ static void __mark_core_id(struct mdesc_handle *hp, u64 node,
                cpu_data(*id).core_id = core_id;
 }
 
-static void __mark_sock_id(struct mdesc_handle *hp, u64 node,
-                          int sock_id)
+static void __mark_max_cache_id(struct mdesc_handle *hp, u64 node,
+                               int max_cache_id)
 {
        const u64 *id = mdesc_get_property(hp, node, "id", NULL);
 
-       if (*id < num_possible_cpus())
-               cpu_data(*id).sock_id = sock_id;
+       if (*id < num_possible_cpus()) {
+               cpu_data(*id).max_cache_id = max_cache_id;
+
+               /**
+                * On systems without explicit socket descriptions socket
+                * is max_cache_id
+                */
+               cpu_data(*id).sock_id = max_cache_id;
+       }
 }
 
 static void mark_core_ids(struct mdesc_handle *hp, u64 mp,
@@ -660,10 +667,11 @@ static void mark_core_ids(struct mdesc_handle *hp, u64 mp,
        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)
+static void mark_max_cache_ids(struct mdesc_handle *hp, u64 mp,
+                              int max_cache_id)
 {
-       find_back_node_value(hp, mp, "cpu", __mark_sock_id, sock_id, 10);
+       find_back_node_value(hp, mp, "cpu", __mark_max_cache_id,
+                            max_cache_id, 10);
 }
 
 static void set_core_ids(struct mdesc_handle *hp)
@@ -694,14 +702,15 @@ static void set_core_ids(struct mdesc_handle *hp)
        }
 }
 
-static int set_sock_ids_by_cache(struct mdesc_handle *hp, int level)
+static int set_max_cache_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.
+       /**
+        * Identify unique highest level of shared cache by looking for cpus
+        * backpointed to by shared level N caches.
         */
        mdesc_for_each_node_by_name(hp, mp, "cache") {
                const u64 *cur_lvl;
@@ -709,8 +718,7 @@ static int set_sock_ids_by_cache(struct mdesc_handle *hp, int level)
                cur_lvl = mdesc_get_property(hp, mp, "level", NULL);
                if (*cur_lvl != level)
                        continue;
-
-               mark_sock_ids(hp, mp, idx);
+               mark_max_cache_ids(hp, mp, idx);
                idx++;
                fnd = 1;
        }
@@ -745,15 +753,17 @@ 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.
+       /**
+        * Find the highest level of shared cache which pre-T7 is also
+        * the socket.
         */
+       if (!set_max_cache_ids_by_cache(hp, 3))
+               set_max_cache_ids_by_cache(hp, 2);
+
+       /* If machine description exposes sockets data use it.*/
        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);
+               set_sock_ids_by_socket(hp, mp);
 }
 
 static void mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id)
index db57d8acdc01cf52aeb1664acdc35fef77b3a21a..06981cc716b68022712dc3a872e611565e4e4817 100644 (file)
@@ -44,6 +44,9 @@ static struct vpci_version vpci_versions[] = {
        { .major = 1, .minor = 1 },
 };
 
+static unsigned long vatu_major = 1;
+static unsigned long vatu_minor = 1;
+
 #define PGLIST_NENTS   (PAGE_SIZE / sizeof(u64))
 
 struct iommu_batch {
@@ -69,34 +72,57 @@ static inline void iommu_batch_start(struct device *dev, unsigned long prot, uns
 }
 
 /* Interrupts must be disabled.  */
-static long iommu_batch_flush(struct iommu_batch *p)
+static long iommu_batch_flush(struct iommu_batch *p, u64 mask)
 {
        struct pci_pbm_info *pbm = p->dev->archdata.host_controller;
+       u64 *pglist = p->pglist;
+       u64 index_count;
        unsigned long devhandle = pbm->devhandle;
        unsigned long prot = p->prot;
        unsigned long entry = p->entry;
-       u64 *pglist = p->pglist;
        unsigned long npages = p->npages;
+       unsigned long iotsb_num;
+       unsigned long ret;
+       long num;
 
        /* VPCI maj=1, min=[0,1] only supports read and write */
        if (vpci_major < 2)
                prot &= (HV_PCI_MAP_ATTR_READ | HV_PCI_MAP_ATTR_WRITE);
 
        while (npages != 0) {
-               long num;
-
-               num = pci_sun4v_iommu_map(devhandle, HV_PCI_TSBID(0, entry),
-                                         npages, prot, __pa(pglist));
-               if (unlikely(num < 0)) {
-                       if (printk_ratelimit())
-                               printk("iommu_batch_flush: IOMMU map of "
-                                      "[%08lx:%08llx:%lx:%lx:%lx] failed with "
-                                      "status %ld\n",
-                                      devhandle, HV_PCI_TSBID(0, entry),
-                                      npages, prot, __pa(pglist), num);
-                       return -1;
+               if (mask <= DMA_BIT_MASK(32)) {
+                       num = pci_sun4v_iommu_map(devhandle,
+                                                 HV_PCI_TSBID(0, entry),
+                                                 npages,
+                                                 prot,
+                                                 __pa(pglist));
+                       if (unlikely(num < 0)) {
+                               pr_err_ratelimited("%s: IOMMU map of [%08lx:%08llx:%lx:%lx:%lx] failed with status %ld\n",
+                                                  __func__,
+                                                  devhandle,
+                                                  HV_PCI_TSBID(0, entry),
+                                                  npages, prot, __pa(pglist),
+                                                  num);
+                               return -1;
+                       }
+               } else {
+                       index_count = HV_PCI_IOTSB_INDEX_COUNT(npages, entry),
+                       iotsb_num = pbm->iommu->atu->iotsb->iotsb_num;
+                       ret = pci_sun4v_iotsb_map(devhandle,
+                                                 iotsb_num,
+                                                 index_count,
+                                                 prot,
+                                                 __pa(pglist),
+                                                 &num);
+                       if (unlikely(ret != HV_EOK)) {
+                               pr_err_ratelimited("%s: ATU map of [%08lx:%lx:%llx:%lx:%lx] failed with status %ld\n",
+                                                  __func__,
+                                                  devhandle, iotsb_num,
+                                                  index_count, prot,
+                                                  __pa(pglist), ret);
+                               return -1;
+                       }
                }
-
                entry += num;
                npages -= num;
                pglist += num;
@@ -108,19 +134,19 @@ static long iommu_batch_flush(struct iommu_batch *p)
        return 0;
 }
 
-static inline void iommu_batch_new_entry(unsigned long entry)
+static inline void iommu_batch_new_entry(unsigned long entry, u64 mask)
 {
        struct iommu_batch *p = this_cpu_ptr(&iommu_batch);
 
        if (p->entry + p->npages == entry)
                return;
        if (p->entry != ~0UL)
-               iommu_batch_flush(p);
+               iommu_batch_flush(p, mask);
        p->entry = entry;
 }
 
 /* Interrupts must be disabled.  */
-static inline long iommu_batch_add(u64 phys_page)
+static inline long iommu_batch_add(u64 phys_page, u64 mask)
 {
        struct iommu_batch *p = this_cpu_ptr(&iommu_batch);
 
@@ -128,28 +154,31 @@ static inline long iommu_batch_add(u64 phys_page)
 
        p->pglist[p->npages++] = phys_page;
        if (p->npages == PGLIST_NENTS)
-               return iommu_batch_flush(p);
+               return iommu_batch_flush(p, mask);
 
        return 0;
 }
 
 /* Interrupts must be disabled.  */
-static inline long iommu_batch_end(void)
+static inline long iommu_batch_end(u64 mask)
 {
        struct iommu_batch *p = this_cpu_ptr(&iommu_batch);
 
        BUG_ON(p->npages >= PGLIST_NENTS);
 
-       return iommu_batch_flush(p);
+       return iommu_batch_flush(p, mask);
 }
 
 static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
                                   dma_addr_t *dma_addrp, gfp_t gfp,
                                   unsigned long attrs)
 {
+       u64 mask;
        unsigned long flags, order, first_page, npages, n;
        unsigned long prot = 0;
        struct iommu *iommu;
+       struct atu *atu;
+       struct iommu_map_table *tbl;
        struct page *page;
        void *ret;
        long entry;
@@ -174,14 +203,21 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
        memset((char *)first_page, 0, PAGE_SIZE << order);
 
        iommu = dev->archdata.iommu;
+       atu = iommu->atu;
+
+       mask = dev->coherent_dma_mask;
+       if (mask <= DMA_BIT_MASK(32))
+               tbl = &iommu->tbl;
+       else
+               tbl = &atu->tbl;
 
-       entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL,
+       entry = iommu_tbl_range_alloc(dev, tbl, npages, NULL,
                                      (unsigned long)(-1), 0);
 
        if (unlikely(entry == IOMMU_ERROR_CODE))
                goto range_alloc_fail;
 
-       *dma_addrp = (iommu->tbl.table_map_base + (entry << IO_PAGE_SHIFT));
+       *dma_addrp = (tbl->table_map_base + (entry << IO_PAGE_SHIFT));
        ret = (void *) first_page;
        first_page = __pa(first_page);
 
@@ -193,12 +229,12 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
                          entry);
 
        for (n = 0; n < npages; n++) {
-               long err = iommu_batch_add(first_page + (n * PAGE_SIZE));
+               long err = iommu_batch_add(first_page + (n * PAGE_SIZE), mask);
                if (unlikely(err < 0L))
                        goto iommu_map_fail;
        }
 
-       if (unlikely(iommu_batch_end() < 0L))
+       if (unlikely(iommu_batch_end(mask) < 0L))
                goto iommu_map_fail;
 
        local_irq_restore(flags);
@@ -206,25 +242,71 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
        return ret;
 
 iommu_map_fail:
-       iommu_tbl_range_free(&iommu->tbl, *dma_addrp, npages, IOMMU_ERROR_CODE);
+       iommu_tbl_range_free(tbl, *dma_addrp, npages, IOMMU_ERROR_CODE);
 
 range_alloc_fail:
        free_pages(first_page, order);
        return NULL;
 }
 
-static void dma_4v_iommu_demap(void *demap_arg, unsigned long entry,
-                              unsigned long npages)
+unsigned long dma_4v_iotsb_bind(unsigned long devhandle,
+                               unsigned long iotsb_num,
+                               struct pci_bus *bus_dev)
+{
+       struct pci_dev *pdev;
+       unsigned long err;
+       unsigned int bus;
+       unsigned int device;
+       unsigned int fun;
+
+       list_for_each_entry(pdev, &bus_dev->devices, bus_list) {
+               if (pdev->subordinate) {
+                       /* No need to bind pci bridge */
+                       dma_4v_iotsb_bind(devhandle, iotsb_num,
+                                         pdev->subordinate);
+               } else {
+                       bus = bus_dev->number;
+                       device = PCI_SLOT(pdev->devfn);
+                       fun = PCI_FUNC(pdev->devfn);
+                       err = pci_sun4v_iotsb_bind(devhandle, iotsb_num,
+                                                  HV_PCI_DEVICE_BUILD(bus,
+                                                                      device,
+                                                                      fun));
+
+                       /* If bind fails for one device it is going to fail
+                        * for rest of the devices because we are sharing
+                        * IOTSB. So in case of failure simply return with
+                        * error.
+                        */
+                       if (err)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+static void dma_4v_iommu_demap(struct device *dev, unsigned long devhandle,
+                              dma_addr_t dvma, unsigned long iotsb_num,
+                              unsigned long entry, unsigned long npages)
 {
-       u32 devhandle = *(u32 *)demap_arg;
        unsigned long num, flags;
+       unsigned long ret;
 
        local_irq_save(flags);
        do {
-               num = pci_sun4v_iommu_demap(devhandle,
-                                           HV_PCI_TSBID(0, entry),
-                                           npages);
-
+               if (dvma <= DMA_BIT_MASK(32)) {
+                       num = pci_sun4v_iommu_demap(devhandle,
+                                                   HV_PCI_TSBID(0, entry),
+                                                   npages);
+               } else {
+                       ret = pci_sun4v_iotsb_demap(devhandle, iotsb_num,
+                                                   entry, npages, &num);
+                       if (unlikely(ret != HV_EOK)) {
+                               pr_err_ratelimited("pci_iotsb_demap() failed with error: %ld\n",
+                                                  ret);
+                       }
+               }
                entry += num;
                npages -= num;
        } while (npages != 0);
@@ -236,16 +318,28 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
 {
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
+       struct atu *atu;
+       struct iommu_map_table *tbl;
        unsigned long order, npages, entry;
+       unsigned long iotsb_num;
        u32 devhandle;
 
        npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
        iommu = dev->archdata.iommu;
        pbm = dev->archdata.host_controller;
+       atu = iommu->atu;
        devhandle = pbm->devhandle;
-       entry = ((dvma - iommu->tbl.table_map_base) >> IO_PAGE_SHIFT);
-       dma_4v_iommu_demap(&devhandle, entry, npages);
-       iommu_tbl_range_free(&iommu->tbl, dvma, npages, IOMMU_ERROR_CODE);
+
+       if (dvma <= DMA_BIT_MASK(32)) {
+               tbl = &iommu->tbl;
+               iotsb_num = 0; /* we don't care for legacy iommu */
+       } else {
+               tbl = &atu->tbl;
+               iotsb_num = atu->iotsb->iotsb_num;
+       }
+       entry = ((dvma - tbl->table_map_base) >> IO_PAGE_SHIFT);
+       dma_4v_iommu_demap(dev, devhandle, dvma, iotsb_num, entry, npages);
+       iommu_tbl_range_free(tbl, dvma, npages, IOMMU_ERROR_CODE);
        order = get_order(size);
        if (order < 10)
                free_pages((unsigned long)cpu, order);
@@ -257,13 +351,17 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
                                  unsigned long attrs)
 {
        struct iommu *iommu;
+       struct atu *atu;
+       struct iommu_map_table *tbl;
+       u64 mask;
        unsigned long flags, npages, oaddr;
        unsigned long i, base_paddr;
-       u32 bus_addr, ret;
        unsigned long prot;
+       dma_addr_t bus_addr, ret;
        long entry;
 
        iommu = dev->archdata.iommu;
+       atu = iommu->atu;
 
        if (unlikely(direction == DMA_NONE))
                goto bad;
@@ -272,13 +370,19 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
        npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
 
-       entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL,
+       mask = *dev->dma_mask;
+       if (mask <= DMA_BIT_MASK(32))
+               tbl = &iommu->tbl;
+       else
+               tbl = &atu->tbl;
+
+       entry = iommu_tbl_range_alloc(dev, tbl, npages, NULL,
                                      (unsigned long)(-1), 0);
 
        if (unlikely(entry == IOMMU_ERROR_CODE))
                goto bad;
 
-       bus_addr = (iommu->tbl.table_map_base + (entry << IO_PAGE_SHIFT));
+       bus_addr = (tbl->table_map_base + (entry << IO_PAGE_SHIFT));
        ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
        base_paddr = __pa(oaddr & IO_PAGE_MASK);
        prot = HV_PCI_MAP_ATTR_READ;
@@ -293,11 +397,11 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
        iommu_batch_start(dev, prot, entry);
 
        for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) {
-               long err = iommu_batch_add(base_paddr);
+               long err = iommu_batch_add(base_paddr, mask);
                if (unlikely(err < 0L))
                        goto iommu_map_fail;
        }
-       if (unlikely(iommu_batch_end() < 0L))
+       if (unlikely(iommu_batch_end(mask) < 0L))
                goto iommu_map_fail;
 
        local_irq_restore(flags);
@@ -310,7 +414,7 @@ bad:
        return DMA_ERROR_CODE;
 
 iommu_map_fail:
-       iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, IOMMU_ERROR_CODE);
+       iommu_tbl_range_free(tbl, bus_addr, npages, IOMMU_ERROR_CODE);
        return DMA_ERROR_CODE;
 }
 
@@ -320,7 +424,10 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
 {
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
+       struct atu *atu;
+       struct iommu_map_table *tbl;
        unsigned long npages;
+       unsigned long iotsb_num;
        long entry;
        u32 devhandle;
 
@@ -332,14 +439,23 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
 
        iommu = dev->archdata.iommu;
        pbm = dev->archdata.host_controller;
+       atu = iommu->atu;
        devhandle = pbm->devhandle;
 
        npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
        bus_addr &= IO_PAGE_MASK;
-       entry = (bus_addr - iommu->tbl.table_map_base) >> IO_PAGE_SHIFT;
-       dma_4v_iommu_demap(&devhandle, entry, npages);
-       iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, IOMMU_ERROR_CODE);
+
+       if (bus_addr <= DMA_BIT_MASK(32)) {
+               iotsb_num = 0; /* we don't care for legacy iommu */
+               tbl = &iommu->tbl;
+       } else {
+               iotsb_num = atu->iotsb->iotsb_num;
+               tbl = &atu->tbl;
+       }
+       entry = (bus_addr - tbl->table_map_base) >> IO_PAGE_SHIFT;
+       dma_4v_iommu_demap(dev, devhandle, bus_addr, iotsb_num, entry, npages);
+       iommu_tbl_range_free(tbl, bus_addr, npages, IOMMU_ERROR_CODE);
 }
 
 static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
@@ -353,12 +469,17 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
        unsigned long seg_boundary_size;
        int outcount, incount, i;
        struct iommu *iommu;
+       struct atu *atu;
+       struct iommu_map_table *tbl;
+       u64 mask;
        unsigned long base_shift;
        long err;
 
        BUG_ON(direction == DMA_NONE);
 
        iommu = dev->archdata.iommu;
+       atu = iommu->atu;
+
        if (nelems == 0 || !iommu)
                return 0;
        
@@ -384,7 +505,15 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
        max_seg_size = dma_get_max_seg_size(dev);
        seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
                                  IO_PAGE_SIZE) >> IO_PAGE_SHIFT;
-       base_shift = iommu->tbl.table_map_base >> IO_PAGE_SHIFT;
+
+       mask = *dev->dma_mask;
+       if (mask <= DMA_BIT_MASK(32))
+               tbl = &iommu->tbl;
+       else
+               tbl = &atu->tbl;
+
+       base_shift = tbl->table_map_base >> IO_PAGE_SHIFT;
+
        for_each_sg(sglist, s, nelems, i) {
                unsigned long paddr, npages, entry, out_entry = 0, slen;
 
@@ -397,27 +526,26 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
                /* Allocate iommu entries for that segment */
                paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
                npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE);
-               entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages,
+               entry = iommu_tbl_range_alloc(dev, tbl, npages,
                                              &handle, (unsigned long)(-1), 0);
 
                /* Handle failure */
                if (unlikely(entry == IOMMU_ERROR_CODE)) {
-                       if (printk_ratelimit())
-                               printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx"
-                                      " npages %lx\n", iommu, paddr, npages);
+                       pr_err_ratelimited("iommu_alloc failed, iommu %p paddr %lx npages %lx\n",
+                                          tbl, paddr, npages);
                        goto iommu_map_failed;
                }
 
-               iommu_batch_new_entry(entry);
+               iommu_batch_new_entry(entry, mask);
 
                /* Convert entry to a dma_addr_t */
-               dma_addr = iommu->tbl.table_map_base + (entry << IO_PAGE_SHIFT);
+               dma_addr = tbl->table_map_base + (entry << IO_PAGE_SHIFT);
                dma_addr |= (s->offset & ~IO_PAGE_MASK);
 
                /* Insert into HW table */
                paddr &= IO_PAGE_MASK;
                while (npages--) {
-                       err = iommu_batch_add(paddr);
+                       err = iommu_batch_add(paddr, mask);
                        if (unlikely(err < 0L))
                                goto iommu_map_failed;
                        paddr += IO_PAGE_SIZE;
@@ -452,7 +580,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
                dma_next = dma_addr + slen;
        }
 
-       err = iommu_batch_end();
+       err = iommu_batch_end(mask);
 
        if (unlikely(err < 0L))
                goto iommu_map_failed;
@@ -475,7 +603,7 @@ iommu_map_failed:
                        vaddr = s->dma_address & IO_PAGE_MASK;
                        npages = iommu_num_pages(s->dma_address, s->dma_length,
                                                 IO_PAGE_SIZE);
-                       iommu_tbl_range_free(&iommu->tbl, vaddr, npages,
+                       iommu_tbl_range_free(tbl, vaddr, npages,
                                             IOMMU_ERROR_CODE);
                        /* XXX demap? XXX */
                        s->dma_address = DMA_ERROR_CODE;
@@ -496,13 +624,16 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
        struct pci_pbm_info *pbm;
        struct scatterlist *sg;
        struct iommu *iommu;
+       struct atu *atu;
        unsigned long flags, entry;
+       unsigned long iotsb_num;
        u32 devhandle;
 
        BUG_ON(direction == DMA_NONE);
 
        iommu = dev->archdata.iommu;
        pbm = dev->archdata.host_controller;
+       atu = iommu->atu;
        devhandle = pbm->devhandle;
        
        local_irq_save(flags);
@@ -512,15 +643,24 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
                dma_addr_t dma_handle = sg->dma_address;
                unsigned int len = sg->dma_length;
                unsigned long npages;
-               struct iommu_map_table *tbl = &iommu->tbl;
+               struct iommu_map_table *tbl;
                unsigned long shift = IO_PAGE_SHIFT;
 
                if (!len)
                        break;
                npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE);
+
+               if (dma_handle <= DMA_BIT_MASK(32)) {
+                       iotsb_num = 0; /* we don't care for legacy iommu */
+                       tbl = &iommu->tbl;
+               } else {
+                       iotsb_num = atu->iotsb->iotsb_num;
+                       tbl = &atu->tbl;
+               }
                entry = ((dma_handle - tbl->table_map_base) >> shift);
-               dma_4v_iommu_demap(&devhandle, entry, npages);
-               iommu_tbl_range_free(&iommu->tbl, dma_handle, npages,
+               dma_4v_iommu_demap(dev, devhandle, dma_handle, iotsb_num,
+                                  entry, npages);
+               iommu_tbl_range_free(tbl, dma_handle, npages,
                                     IOMMU_ERROR_CODE);
                sg = sg_next(sg);
        }
@@ -581,6 +721,132 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
        return cnt;
 }
 
+static int pci_sun4v_atu_alloc_iotsb(struct pci_pbm_info *pbm)
+{
+       struct atu *atu = pbm->iommu->atu;
+       struct atu_iotsb *iotsb;
+       void *table;
+       u64 table_size;
+       u64 iotsb_num;
+       unsigned long order;
+       unsigned long err;
+
+       iotsb = kzalloc(sizeof(*iotsb), GFP_KERNEL);
+       if (!iotsb) {
+               err = -ENOMEM;
+               goto out_err;
+       }
+       atu->iotsb = iotsb;
+
+       /* calculate size of IOTSB */
+       table_size = (atu->size / IO_PAGE_SIZE) * 8;
+       order = get_order(table_size);
+       table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
+       if (!table) {
+               err = -ENOMEM;
+               goto table_failed;
+       }
+       iotsb->table = table;
+       iotsb->ra = __pa(table);
+       iotsb->dvma_size = atu->size;
+       iotsb->dvma_base = atu->base;
+       iotsb->table_size = table_size;
+       iotsb->page_size = IO_PAGE_SIZE;
+
+       /* configure and register IOTSB with HV */
+       err = pci_sun4v_iotsb_conf(pbm->devhandle,
+                                  iotsb->ra,
+                                  iotsb->table_size,
+                                  iotsb->page_size,
+                                  iotsb->dvma_base,
+                                  &iotsb_num);
+       if (err) {
+               pr_err(PFX "pci_iotsb_conf failed error: %ld\n", err);
+               goto iotsb_conf_failed;
+       }
+       iotsb->iotsb_num = iotsb_num;
+
+       err = dma_4v_iotsb_bind(pbm->devhandle, iotsb_num, pbm->pci_bus);
+       if (err) {
+               pr_err(PFX "pci_iotsb_bind failed error: %ld\n", err);
+               goto iotsb_conf_failed;
+       }
+
+       return 0;
+
+iotsb_conf_failed:
+       free_pages((unsigned long)table, order);
+table_failed:
+       kfree(iotsb);
+out_err:
+       return err;
+}
+
+static int pci_sun4v_atu_init(struct pci_pbm_info *pbm)
+{
+       struct atu *atu = pbm->iommu->atu;
+       unsigned long err;
+       const u64 *ranges;
+       u64 map_size, num_iotte;
+       u64 dma_mask;
+       const u32 *page_size;
+       int len;
+
+       ranges = of_get_property(pbm->op->dev.of_node, "iommu-address-ranges",
+                                &len);
+       if (!ranges) {
+               pr_err(PFX "No iommu-address-ranges\n");
+               return -EINVAL;
+       }
+
+       page_size = of_get_property(pbm->op->dev.of_node, "iommu-pagesizes",
+                                   NULL);
+       if (!page_size) {
+               pr_err(PFX "No iommu-pagesizes\n");
+               return -EINVAL;
+       }
+
+       /* There are 4 iommu-address-ranges supported. Each range is pair of
+        * {base, size}. The ranges[0] and ranges[1] are 32bit address space
+        * while ranges[2] and ranges[3] are 64bit space.  We want to use 64bit
+        * address ranges to support 64bit addressing. Because 'size' for
+        * address ranges[2] and ranges[3] are same we can select either of
+        * ranges[2] or ranges[3] for mapping. However due to 'size' is too
+        * large for OS to allocate IOTSB we are using fix size 32G
+        * (ATU_64_SPACE_SIZE) which is more than enough for all PCIe devices
+        * to share.
+        */
+       atu->ranges = (struct atu_ranges *)ranges;
+       atu->base = atu->ranges[3].base;
+       atu->size = ATU_64_SPACE_SIZE;
+
+       /* Create IOTSB */
+       err = pci_sun4v_atu_alloc_iotsb(pbm);
+       if (err) {
+               pr_err(PFX "Error creating ATU IOTSB\n");
+               return err;
+       }
+
+       /* Create ATU iommu map.
+        * One bit represents one iotte in IOTSB table.
+        */
+       dma_mask = (roundup_pow_of_two(atu->size) - 1UL);
+       num_iotte = atu->size / IO_PAGE_SIZE;
+       map_size = num_iotte / 8;
+       atu->tbl.table_map_base = atu->base;
+       atu->dma_addr_mask = dma_mask;
+       atu->tbl.map = kzalloc(map_size, GFP_KERNEL);
+       if (!atu->tbl.map)
+               return -ENOMEM;
+
+       iommu_tbl_pool_init(&atu->tbl, num_iotte, IO_PAGE_SHIFT,
+                           NULL, false /* no large_pool */,
+                           0 /* default npools */,
+                           false /* want span boundary checking */);
+
+       return 0;
+}
+
 static int pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
 {
        static const u32 vdma_default[] = { 0x80000000, 0x80000000 };
@@ -918,6 +1184,18 @@ static int pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
 
        pci_sun4v_scan_bus(pbm, &op->dev);
 
+       /* if atu_init fails its not complete failure.
+        * we can still continue using legacy iommu.
+        */
+       if (pbm->iommu->atu) {
+               err = pci_sun4v_atu_init(pbm);
+               if (err) {
+                       kfree(pbm->iommu->atu);
+                       pbm->iommu->atu = NULL;
+                       pr_err(PFX "ATU init failed, err=%d\n", err);
+               }
+       }
+
        pbm->next = pci_pbm_root;
        pci_pbm_root = pbm;
 
@@ -931,8 +1209,10 @@ static int pci_sun4v_probe(struct platform_device *op)
        struct pci_pbm_info *pbm;
        struct device_node *dp;
        struct iommu *iommu;
+       struct atu *atu;
        u32 devhandle;
        int i, err = -ENODEV;
+       static bool hv_atu = true;
 
        dp = op->dev.of_node;
 
@@ -954,6 +1234,19 @@ static int pci_sun4v_probe(struct platform_device *op)
                pr_info(PFX "Registered hvapi major[%lu] minor[%lu]\n",
                        vpci_major, vpci_minor);
 
+               err = sun4v_hvapi_register(HV_GRP_ATU, vatu_major, &vatu_minor);
+               if (err) {
+                       /* don't return an error if we fail to register the
+                        * ATU group, but ATU hcalls won't be available.
+                        */
+                       hv_atu = false;
+                       pr_err(PFX "Could not register hvapi ATU err=%d\n",
+                              err);
+               } else {
+                       pr_info(PFX "Registered hvapi ATU major[%lu] minor[%lu]\n",
+                               vatu_major, vatu_minor);
+               }
+
                dma_ops = &sun4v_dma_ops;
        }
 
@@ -991,6 +1284,14 @@ static int pci_sun4v_probe(struct platform_device *op)
        }
 
        pbm->iommu = iommu;
+       iommu->atu = NULL;
+       if (hv_atu) {
+               atu = kzalloc(sizeof(*atu), GFP_KERNEL);
+               if (!atu)
+                       pr_err(PFX "Could not allocate atu\n");
+               else
+                       iommu->atu = atu;
+       }
 
        err = pci_sun4v_pbm_init(pbm, op, devhandle);
        if (err)
@@ -1001,6 +1302,7 @@ static int pci_sun4v_probe(struct platform_device *op)
        return 0;
 
 out_free_iommu:
+       kfree(iommu->atu);
        kfree(pbm->iommu);
 
 out_free_controller:
index 5642212390b2ea7911cea77b1fcc2f6c133f882b..22603a4e48bf1883d3bb72292ec23e10ee6673b3 100644 (file)
@@ -89,4 +89,25 @@ unsigned long pci_sun4v_msg_setvalid(unsigned long devhandle,
                                     unsigned long msinum,
                                     unsigned long valid);
 
+/* Sun4v HV IOMMU v2 APIs */
+unsigned long pci_sun4v_iotsb_conf(unsigned long devhandle,
+                                  unsigned long ra,
+                                  unsigned long table_size,
+                                  unsigned long page_size,
+                                  unsigned long dvma_base,
+                                  u64 *iotsb_num);
+unsigned long pci_sun4v_iotsb_bind(unsigned long devhandle,
+                                  unsigned long iotsb_num,
+                                  unsigned int pci_device);
+unsigned long pci_sun4v_iotsb_map(unsigned long devhandle,
+                                 unsigned long iotsb_num,
+                                 unsigned long iotsb_index_iottes,
+                                 unsigned long io_attributes,
+                                 unsigned long io_page_list_pa,
+                                 long *mapped);
+unsigned long pci_sun4v_iotsb_demap(unsigned long devhandle,
+                                   unsigned long iotsb_num,
+                                   unsigned long iotsb_index,
+                                   unsigned long iottes,
+                                   unsigned long *demapped);
 #endif /* !(_PCI_SUN4V_H) */
index e606d46c68159a9c773dfd571fb60b6659882055..578f09657916305b2aab785e2c0eca683863987a 100644 (file)
@@ -360,3 +360,71 @@ ENTRY(pci_sun4v_msg_setvalid)
         mov    %o0, %o0
 ENDPROC(pci_sun4v_msg_setvalid)
 
+       /*
+        * %o0: devhandle
+        * %o1: r_addr
+        * %o2: size
+        * %o3: pagesize
+        * %o4: virt
+        * %o5: &iotsb_num/&iotsb_handle
+        *
+        * returns %o0: status
+        *         %o1: iotsb_num/iotsb_handle
+        */
+ENTRY(pci_sun4v_iotsb_conf)
+       mov     %o5, %g1
+       mov     HV_FAST_PCI_IOTSB_CONF, %o5
+       ta      HV_FAST_TRAP
+       retl
+        stx    %o1, [%g1]
+ENDPROC(pci_sun4v_iotsb_conf)
+
+       /*
+        * %o0: devhandle
+        * %o1: iotsb_num/iotsb_handle
+        * %o2: pci_device
+        *
+        * returns %o0: status
+        */
+ENTRY(pci_sun4v_iotsb_bind)
+       mov     HV_FAST_PCI_IOTSB_BIND, %o5
+       ta      HV_FAST_TRAP
+       retl
+        nop
+ENDPROC(pci_sun4v_iotsb_bind)
+
+       /*
+        * %o0: devhandle
+        * %o1: iotsb_num/iotsb_handle
+        * %o2: index_count
+        * %o3: iotte_attributes
+        * %o4: io_page_list_p
+        * %o5: &mapped
+        *
+        * returns %o0: status
+        *         %o1: #mapped
+        */
+ENTRY(pci_sun4v_iotsb_map)
+       mov     %o5, %g1
+       mov     HV_FAST_PCI_IOTSB_MAP, %o5
+       ta      HV_FAST_TRAP
+       retl
+        stx    %o1, [%g1]
+ENDPROC(pci_sun4v_iotsb_map)
+
+       /*
+        * %o0: devhandle
+        * %o1: iotsb_num/iotsb_handle
+        * %o2: iotsb_index
+        * %o3: #iottes
+        * %o4: &demapped
+        *
+        * returns %o0: status
+        *         %o1: #demapped
+        */
+ENTRY(pci_sun4v_iotsb_demap)
+       mov     HV_FAST_PCI_IOTSB_DEMAP, %o5
+       ta      HV_FAST_TRAP
+       retl
+        stx    %o1, [%o4]
+ENDPROC(pci_sun4v_iotsb_demap)
index 9ddc4928a089b599568331792097c2bc35ea0be8..ac082dd8c67d5a4f1fbf527145b82bd251fbdc8d 100644 (file)
@@ -127,7 +127,8 @@ static int get_from_target(struct task_struct *target, unsigned long uaddr,
                if (copy_from_user(kbuf, (void __user *) uaddr, len))
                        return -EFAULT;
        } else {
-               int len2 = access_process_vm(target, uaddr, kbuf, len, 0);
+               int len2 = access_process_vm(target, uaddr, kbuf, len,
+                               FOLL_FORCE);
                if (len2 != len)
                        return -EFAULT;
        }
@@ -141,7 +142,8 @@ static int set_to_target(struct task_struct *target, unsigned long uaddr,
                if (copy_to_user((void __user *) uaddr, kbuf, len))
                        return -EFAULT;
        } else {
-               int len2 = access_process_vm(target, uaddr, kbuf, len, 1);
+               int len2 = access_process_vm(target, uaddr, kbuf, len,
+                               FOLL_FORCE | FOLL_WRITE);
                if (len2 != len)
                        return -EFAULT;
        }
@@ -505,7 +507,8 @@ static int genregs32_get(struct task_struct *target,
                                if (access_process_vm(target,
                                                      (unsigned long)
                                                      &reg_window[pos],
-                                                     k, sizeof(*k), 0)
+                                                     k, sizeof(*k),
+                                                     FOLL_FORCE)
                                    != sizeof(*k))
                                        return -EFAULT;
                                k++;
@@ -531,12 +534,14 @@ static int genregs32_get(struct task_struct *target,
                                if (access_process_vm(target,
                                                      (unsigned long)
                                                      &reg_window[pos],
-                                                     &reg, sizeof(reg), 0)
+                                                     &reg, sizeof(reg),
+                                                     FOLL_FORCE)
                                    != sizeof(reg))
                                        return -EFAULT;
                                if (access_process_vm(target,
                                                      (unsigned long) u,
-                                                     &reg, sizeof(reg), 1)
+                                                     &reg, sizeof(reg),
+                                                     FOLL_FORCE | FOLL_WRITE)
                                    != sizeof(reg))
                                        return -EFAULT;
                                pos++;
@@ -615,7 +620,8 @@ static int genregs32_set(struct task_struct *target,
                                                      (unsigned long)
                                                      &reg_window[pos],
                                                      (void *) k,
-                                                     sizeof(*k), 1)
+                                                     sizeof(*k),
+                                                     FOLL_FORCE | FOLL_WRITE)
                                    != sizeof(*k))
                                        return -EFAULT;
                                k++;
@@ -642,13 +648,15 @@ static int genregs32_set(struct task_struct *target,
                                if (access_process_vm(target,
                                                      (unsigned long)
                                                      u,
-                                                     &reg, sizeof(reg), 0)
+                                                     &reg, sizeof(reg),
+                                                     FOLL_FORCE)
                                    != sizeof(reg))
                                        return -EFAULT;
                                if (access_process_vm(target,
                                                      (unsigned long)
                                                      &reg_window[pos],
-                                                     &reg, sizeof(reg), 1)
+                                                     &reg, sizeof(reg),
+                                                     FOLL_FORCE | FOLL_WRITE)
                                    != sizeof(reg))
                                        return -EFAULT;
                                pos++;
index c3c12efe0bc004053fea6b49c2f34e51e1ffc32f..9c0c8fd0b2922cacd2ad6ad81f3238a707286d69 100644 (file)
@@ -89,7 +89,7 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
        sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
 
        /* 1. Make sure we are not getting garbage from the user */
-       if (!invalid_frame_pointer(sf, sizeof(*sf)))
+       if (invalid_frame_pointer(sf, sizeof(*sf)))
                goto segv_and_exit;
 
        if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
@@ -150,7 +150,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
 
        synchronize_user_stack();
        sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
-       if (!invalid_frame_pointer(sf, sizeof(*sf)))
+       if (invalid_frame_pointer(sf, sizeof(*sf)))
                goto segv;
 
        if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
index d3035ba6cd3181fb2ada3b4f6bbdcf80422a02a8..8182f7caf5b1faa0b5d3cdc3a767411da4ad9f2a 100644 (file)
@@ -63,9 +63,13 @@ cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
 cpumask_t cpu_core_sib_map[NR_CPUS] __read_mostly = {
        [0 ... NR_CPUS-1] = CPU_MASK_NONE };
 
+cpumask_t cpu_core_sib_cache_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);
+EXPORT_SYMBOL(cpu_core_sib_cache_map);
 
 static cpumask_t smp_commenced_mask;
 
@@ -1265,6 +1269,10 @@ void smp_fill_in_sib_core_maps(void)
                unsigned int j;
 
                for_each_present_cpu(j)  {
+                       if (cpu_data(i).max_cache_id ==
+                           cpu_data(j).max_cache_id)
+                               cpumask_set_cpu(j, &cpu_core_sib_cache_map[i]);
+
                        if (cpu_data(i).sock_id == cpu_data(j).sock_id)
                                cpumask_set_cpu(j, &cpu_core_sib_map[i]);
                }
index b7d0bd6b14063bc1e62cfed3c0e32f0b43799396..69a439fa2fc1ac809a969d6651e9b9e0f9be11b9 100644 (file)
@@ -3,11 +3,11 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)               \
+#define EX_LD(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one;  \
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
index 780550e1afc74fd6efe38ef16f73a07ea021a8f2..9947427ce3549799b2e0c5592b3f972e516093ed 100644 (file)
@@ -3,11 +3,11 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)               \
+#define EX_ST(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one;  \
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
index 89358ee948516cf2ad84c60d1e96e021434bcd32..059ea24ad73dcd91b81ef920f3bb18a1475dceb1 100644 (file)
@@ -4,21 +4,18 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #define GLOBAL_SPARE   %g7
 #else
 #define GLOBAL_SPARE   %g5
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)       x
+#define EX_LD(x,y)     x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)       x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)   x
+#define EX_ST(x,y)     x
 #endif
 
 #ifndef LOAD
        .register       %g3,#scratch
 
        .text
+
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)   x
+ENTRY(GEN_retl_o4_1)
+       add     %o4, %o2, %o4
+       retl
+        add    %o4, 1, %o0
+ENDPROC(GEN_retl_o4_1)
+ENTRY(GEN_retl_g1_8)
+       add     %g1, %o2, %g1
+       retl
+        add    %g1, 8, %o0
+ENDPROC(GEN_retl_g1_8)
+ENTRY(GEN_retl_o2_4)
+       retl
+        add    %o2, 4, %o0
+ENDPROC(GEN_retl_o2_4)
+ENTRY(GEN_retl_o2_1)
+       retl
+        add    %o2, 1, %o0
+ENDPROC(GEN_retl_o2_1)
+#endif
+
        .align          64
 
        .globl  FUNC_NAME
@@ -73,8 +93,8 @@ FUNC_NAME:    /* %o0=dst, %o1=src, %o2=len */
        sub             %g0, %o4, %o4
        sub             %o2, %o4, %o2
 1:     subcc           %o4, 1, %o4
-       EX_LD(LOAD(ldub, %o1, %g1))
-       EX_ST(STORE(stb, %g1, %o0))
+       EX_LD(LOAD(ldub, %o1, %g1),GEN_retl_o4_1)
+       EX_ST(STORE(stb, %g1, %o0),GEN_retl_o4_1)
        add             %o1, 1, %o1
        bne,pt          %XCC, 1b
        add             %o0, 1, %o0
@@ -82,8 +102,8 @@ FUNC_NAME:   /* %o0=dst, %o1=src, %o2=len */
        andn            %o2, 0x7, %g1
        sub             %o2, %g1, %o2
 1:     subcc           %g1, 0x8, %g1
-       EX_LD(LOAD(ldx, %o1, %g2))
-       EX_ST(STORE(stx, %g2, %o0))
+       EX_LD(LOAD(ldx, %o1, %g2),GEN_retl_g1_8)
+       EX_ST(STORE(stx, %g2, %o0),GEN_retl_g1_8)
        add             %o1, 0x8, %o1
        bne,pt          %XCC, 1b
         add            %o0, 0x8, %o0
@@ -100,8 +120,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
 
 1:
        subcc           %o2, 4, %o2
-       EX_LD(LOAD(lduw, %o1, %g1))
-       EX_ST(STORE(stw, %g1, %o1 + %o3))
+       EX_LD(LOAD(lduw, %o1, %g1),GEN_retl_o2_4)
+       EX_ST(STORE(stw, %g1, %o1 + %o3),GEN_retl_o2_4)
        bgu,pt          %XCC, 1b
         add            %o1, 4, %o1
 
@@ -111,8 +131,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
        .align          32
 90:
        subcc           %o2, 1, %o2
-       EX_LD(LOAD(ldub, %o1, %g1))
-       EX_ST(STORE(stb, %g1, %o1 + %o3))
+       EX_LD(LOAD(ldub, %o1, %g1),GEN_retl_o2_1)
+       EX_ST(STORE(stb, %g1, %o1 + %o3),GEN_retl_o2_1)
        bgu,pt          %XCC, 90b
         add            %o1, 1, %o1
        retl
index 885f00e81d1ab1f56cd4e47f788f79e653de9d08..69912d2f8b54e903ef040b346371cc27204b9d15 100644 (file)
@@ -38,7 +38,7 @@ lib-$(CONFIG_SPARC64) +=  NG4patch.o NG4copy_page.o NG4clear_page.o NG4memset.o
 lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
 lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
 
-lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
+lib-$(CONFIG_SPARC64) += copy_in_user.o memmove.o
 lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
 
 obj-$(CONFIG_SPARC64) += iomap.o
index d5242b8c4f9495fe4241ee39de01255364e877af..b79a6998d87c82eaeb12f5c1c23ab8fcbc8b10de 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)               \
+#define EX_LD(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_LD_FP(x)            \
+#define EX_LD_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi_fp;\
+       .word 98b, y##_fp;      \
        .text;                  \
        .align 4;
 
index 4e962d993b10cdff7677f8d51e61ad877901facc..dcec55f254ab214dc9aa959c4a575ed58f5a19d8 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)               \
+#define EX_ST(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_ST_FP(x)            \
+#define EX_ST_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi_fp;\
+       .word 98b, y##_fp;      \
        .text;                  \
        .align 4;
 
index d5f585df2f3fc345c87f04fb1a420fa766816cb5..c629dbd121b6e4fe64494c62bcad656747f05ef2 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #define GLOBAL_SPARE   %g7
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)       x
+#define EX_LD(x,y)     x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)    x
+#define EX_LD_FP(x,y)  x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)       x
+#define EX_ST(x,y)     x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)    x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)   x
+#define EX_ST_FP(x,y)  x
 #endif
 
 #ifndef LOAD
        fsrc2           %x6, %f12; \
        fsrc2           %x7, %f14;
 #define FREG_LOAD_1(base, x0) \
-       EX_LD_FP(LOAD(ldd, base + 0x00, %x0))
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1)
 #define FREG_LOAD_2(base, x0, x1) \
-       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD_FP(LOAD(ldd, base + 0x08, %x1));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_3(base, x0, x1, x2) \
-       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD_FP(LOAD(ldd, base + 0x10, %x2));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_4(base, x0, x1, x2, x3) \
-       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD_FP(LOAD(ldd, base + 0x18, %x3));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_5(base, x0, x1, x2, x3, x4) \
-       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
-       EX_LD_FP(LOAD(ldd, base + 0x20, %x4));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x20, %x4), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_6(base, x0, x1, x2, x3, x4, x5) \
-       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
-       EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
-       EX_LD_FP(LOAD(ldd, base + 0x28, %x5));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x20, %x4), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x28, %x5), NG2_retl_o2_plus_g1);
 #define FREG_LOAD_7(base, x0, x1, x2, x3, x4, x5, x6) \
-       EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
-       EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
-       EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
-       EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
-       EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
-       EX_LD_FP(LOAD(ldd, base + 0x28, %x5)); \
-       EX_LD_FP(LOAD(ldd, base + 0x30, %x6));
+       EX_LD_FP(LOAD(ldd, base + 0x00, %x0), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x08, %x1), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x10, %x2), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x18, %x3), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x20, %x4), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x28, %x5), NG2_retl_o2_plus_g1); \
+       EX_LD_FP(LOAD(ldd, base + 0x30, %x6), NG2_retl_o2_plus_g1);
 
        .register       %g2,#scratch
        .register       %g3,#scratch
 
        .text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)   x
+__restore_fp:
+       VISExitHalf
+__restore_asi:
+       retl
+        wr     %g0, ASI_AIUS, %asi
+ENTRY(NG2_retl_o2)
+       ba,pt   %xcc, __restore_asi
+        mov    %o2, %o0
+ENDPROC(NG2_retl_o2)
+ENTRY(NG2_retl_o2_plus_1)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, 1, %o0
+ENDPROC(NG2_retl_o2_plus_1)
+ENTRY(NG2_retl_o2_plus_4)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, 4, %o0
+ENDPROC(NG2_retl_o2_plus_4)
+ENTRY(NG2_retl_o2_plus_8)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, 8, %o0
+ENDPROC(NG2_retl_o2_plus_8)
+ENTRY(NG2_retl_o2_plus_o4_plus_1)
+       add     %o4, 1, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG2_retl_o2_plus_o4_plus_1)
+ENTRY(NG2_retl_o2_plus_o4_plus_8)
+       add     %o4, 8, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG2_retl_o2_plus_o4_plus_8)
+ENTRY(NG2_retl_o2_plus_o4_plus_16)
+       add     %o4, 16, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG2_retl_o2_plus_o4_plus_16)
+ENTRY(NG2_retl_o2_plus_g1_fp)
+       ba,pt   %xcc, __restore_fp
+        add    %o2, %g1, %o0
+ENDPROC(NG2_retl_o2_plus_g1_fp)
+ENTRY(NG2_retl_o2_plus_g1_plus_64_fp)
+       add     %g1, 64, %g1
+       ba,pt   %xcc, __restore_fp
+        add    %o2, %g1, %o0
+ENDPROC(NG2_retl_o2_plus_g1_plus_64_fp)
+ENTRY(NG2_retl_o2_plus_g1_plus_1)
+       add     %g1, 1, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %g1, %o0
+ENDPROC(NG2_retl_o2_plus_g1_plus_1)
+ENTRY(NG2_retl_o2_and_7_plus_o4)
+       and     %o2, 7, %o2
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG2_retl_o2_and_7_plus_o4)
+ENTRY(NG2_retl_o2_and_7_plus_o4_plus_8)
+       and     %o2, 7, %o2
+       add     %o4, 8, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG2_retl_o2_and_7_plus_o4_plus_8)
+#endif
+
        .align          64
 
        .globl  FUNC_NAME
@@ -230,8 +292,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
        sub             %g0, %o4, %o4   ! bytes to align dst
        sub             %o2, %o4, %o2
 1:     subcc           %o4, 1, %o4
-       EX_LD(LOAD(ldub, %o1, %g1))
-       EX_ST(STORE(stb, %g1, %o0))
+       EX_LD(LOAD(ldub, %o1, %g1), NG2_retl_o2_plus_o4_plus_1)
+       EX_ST(STORE(stb, %g1, %o0), NG2_retl_o2_plus_o4_plus_1)
        add             %o1, 1, %o1
        bne,pt          %XCC, 1b
        add             %o0, 1, %o0
@@ -281,11 +343,11 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
         nop
        /* fall through for 0 < low bits < 8 */
 110:   sub             %o4, 64, %g2
-       EX_LD_FP(LOAD_BLK(%g2, %f0))
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+       EX_LD_FP(LOAD_BLK(%g2, %f0), NG2_retl_o2_plus_g1)
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f14, f16)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_8(f16, f18, f20, f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -296,10 +358,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 120:   sub             %o4, 56, %g2
        FREG_LOAD_7(%g2, f0, f2, f4, f6, f8, f10, f12)
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f16, f18)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_7(f18, f20, f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -310,10 +372,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 130:   sub             %o4, 48, %g2
        FREG_LOAD_6(%g2, f0, f2, f4, f6, f8, f10)
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f2, f4, f6, f8, f10, f16, f18, f20)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_6(f20, f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -324,10 +386,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 140:   sub             %o4, 40, %g2
        FREG_LOAD_5(%g2, f0, f2, f4, f6, f8)
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f2, f4, f6, f8, f16, f18, f20, f22)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_5(f22, f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -338,10 +400,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 150:   sub             %o4, 32, %g2
        FREG_LOAD_4(%g2, f0, f2, f4, f6)
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f2, f4, f6, f16, f18, f20, f22, f24)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_4(f24, f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -352,10 +414,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 160:   sub             %o4, 24, %g2
        FREG_LOAD_3(%g2, f0, f2, f4)
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f2, f4, f16, f18, f20, f22, f24, f26)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_3(f26, f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -366,10 +428,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 170:   sub             %o4, 16, %g2
        FREG_LOAD_2(%g2, f0, f2)
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f2, f16, f18, f20, f22, f24, f26, f28)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_2(f28, f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -380,10 +442,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 180:   sub             %o4, 8, %g2
        FREG_LOAD_1(%g2, f0)
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
-       EX_LD_FP(LOAD_BLK(%o4, %f16))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
+       EX_LD_FP(LOAD_BLK(%o4, %f16), NG2_retl_o2_plus_g1)
        FREG_FROB(f0, f16, f18, f20, f22, f24, f26, f28, f30)
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1)
        FREG_MOVE_1(f30)
        subcc           %g1, 64, %g1
        add             %o4, 64, %o4
@@ -393,10 +455,10 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
         nop
 
 190:
-1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+1:     EX_ST_FP(STORE_INIT(%g0, %o4 + %g3), NG2_retl_o2_plus_g1)
        subcc           %g1, 64, %g1
-       EX_LD_FP(LOAD_BLK(%o4, %f0))
-       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
+       EX_LD_FP(LOAD_BLK(%o4, %f0), NG2_retl_o2_plus_g1_plus_64)
+       EX_ST_FP(STORE_BLK(%f0, %o4 + %g3), NG2_retl_o2_plus_g1_plus_64)
        add             %o4, 64, %o4
        bne,pt          %xcc, 1b
         LOAD(prefetch, %o4 + 64, #one_read)
@@ -423,28 +485,28 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        andn            %o2, 0xf, %o4
        and             %o2, 0xf, %o2
 1:     subcc           %o4, 0x10, %o4
-       EX_LD(LOAD(ldx, %o1, %o5))
+       EX_LD(LOAD(ldx, %o1, %o5), NG2_retl_o2_plus_o4_plus_16)
        add             %o1, 0x08, %o1
-       EX_LD(LOAD(ldx, %o1, %g1))
+       EX_LD(LOAD(ldx, %o1, %g1), NG2_retl_o2_plus_o4_plus_16)
        sub             %o1, 0x08, %o1
-       EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE))
+       EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_o4_plus_16)
        add             %o1, 0x8, %o1
-       EX_ST(STORE(stx, %g1, %o1 + GLOBAL_SPARE))
+       EX_ST(STORE(stx, %g1, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_o4_plus_8)
        bgu,pt          %XCC, 1b
         add            %o1, 0x8, %o1
 73:    andcc           %o2, 0x8, %g0
        be,pt           %XCC, 1f
         nop
        sub             %o2, 0x8, %o2
-       EX_LD(LOAD(ldx, %o1, %o5))
-       EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE))
+       EX_LD(LOAD(ldx, %o1, %o5), NG2_retl_o2_plus_8)
+       EX_ST(STORE(stx, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_8)
        add             %o1, 0x8, %o1
 1:     andcc           %o2, 0x4, %g0
        be,pt           %XCC, 1f
         nop
        sub             %o2, 0x4, %o2
-       EX_LD(LOAD(lduw, %o1, %o5))
-       EX_ST(STORE(stw, %o5, %o1 + GLOBAL_SPARE))
+       EX_LD(LOAD(lduw, %o1, %o5), NG2_retl_o2_plus_4)
+       EX_ST(STORE(stw, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_4)
        add             %o1, 0x4, %o1
 1:     cmp             %o2, 0
        be,pt           %XCC, 85f
@@ -460,8 +522,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
        sub             %o2, %g1, %o2
 
 1:     subcc           %g1, 1, %g1
-       EX_LD(LOAD(ldub, %o1, %o5))
-       EX_ST(STORE(stb, %o5, %o1 + GLOBAL_SPARE))
+       EX_LD(LOAD(ldub, %o1, %o5), NG2_retl_o2_plus_g1_plus_1)
+       EX_ST(STORE(stb, %o5, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_g1_plus_1)
        bgu,pt          %icc, 1b
         add            %o1, 1, %o1
 
@@ -477,16 +539,16 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 8:     mov             64, GLOBAL_SPARE
        andn            %o1, 0x7, %o1
-       EX_LD(LOAD(ldx, %o1, %g2))
+       EX_LD(LOAD(ldx, %o1, %g2), NG2_retl_o2)
        sub             GLOBAL_SPARE, %g1, GLOBAL_SPARE
        andn            %o2, 0x7, %o4
        sllx            %g2, %g1, %g2
 1:     add             %o1, 0x8, %o1
-       EX_LD(LOAD(ldx, %o1, %g3))
+       EX_LD(LOAD(ldx, %o1, %g3), NG2_retl_o2_and_7_plus_o4)
        subcc           %o4, 0x8, %o4
        srlx            %g3, GLOBAL_SPARE, %o5
        or              %o5, %g2, %o5
-       EX_ST(STORE(stx, %o5, %o0))
+       EX_ST(STORE(stx, %o5, %o0), NG2_retl_o2_and_7_plus_o4_plus_8)
        add             %o0, 0x8, %o0
        bgu,pt          %icc, 1b
         sllx           %g3, %g1, %g2
@@ -506,8 +568,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
 
 1:
        subcc           %o2, 4, %o2
-       EX_LD(LOAD(lduw, %o1, %g1))
-       EX_ST(STORE(stw, %g1, %o1 + GLOBAL_SPARE))
+       EX_LD(LOAD(lduw, %o1, %g1), NG2_retl_o2_plus_4)
+       EX_ST(STORE(stw, %g1, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_4)
        bgu,pt          %XCC, 1b
         add            %o1, 4, %o1
 
@@ -517,8 +579,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
        .align          32
 90:
        subcc           %o2, 1, %o2
-       EX_LD(LOAD(ldub, %o1, %g1))
-       EX_ST(STORE(stb, %g1, %o1 + GLOBAL_SPARE))
+       EX_LD(LOAD(ldub, %o1, %g1), NG2_retl_o2_plus_1)
+       EX_ST(STORE(stb, %g1, %o1 + GLOBAL_SPARE), NG2_retl_o2_plus_1)
        bgu,pt          %XCC, 90b
         add            %o1, 1, %o1
        retl
index 2e8ee7ad07a9ce06129cd63c4129ccade674ab77..16a286c1a52836ee92b2a7d6bac66d3341b0f905 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)               \
+#define EX_LD(x, y)            \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_LD_FP(x)            \
+#define EX_LD_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi_fp;\
+       .word 98b, y##_fp;      \
        .text;                  \
        .align 4;
 
index be0bf4590df8971ddf29a81153f05de7c0ef30da..6b0276ffc858c4777d95dffcff95f048dd340cc2 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)               \
+#define EX_ST(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_ST_FP(x)            \
+#define EX_ST_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_asi_fp;\
+       .word 98b, y##_fp;      \
        .text;                  \
        .align 4;
 
index 8e13ee1f4454ea2b6478d302a9a1048bfeb60aff..75bb93b1437f7f6f29ab17c96bc0b4c322f2a373 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #define GLOBAL_SPARE   %g7
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)       x
+#define EX_LD(x,y)     x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)    x
+#define EX_LD_FP(x,y)  x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)       x
+#define EX_ST(x,y)     x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)    x
+#define EX_ST_FP(x,y)  x
 #endif
 
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)   x
-#endif
 
 #ifndef LOAD
 #define LOAD(type,addr,dest)   type [addr], dest
        .register       %g3,#scratch
 
        .text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)   x
+__restore_asi_fp:
+       VISExitHalf
+__restore_asi:
+       retl
+        wr     %g0, ASI_AIUS, %asi
+
+ENTRY(NG4_retl_o2)
+       ba,pt   %xcc, __restore_asi
+        mov    %o2, %o0
+ENDPROC(NG4_retl_o2)
+ENTRY(NG4_retl_o2_plus_1)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, 1, %o0
+ENDPROC(NG4_retl_o2_plus_1)
+ENTRY(NG4_retl_o2_plus_4)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, 4, %o0
+ENDPROC(NG4_retl_o2_plus_4)
+ENTRY(NG4_retl_o2_plus_o5)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5)
+ENTRY(NG4_retl_o2_plus_o5_plus_4)
+       add     %o5, 4, %o5
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_4)
+ENTRY(NG4_retl_o2_plus_o5_plus_8)
+       add     %o5, 8, %o5
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_8)
+ENTRY(NG4_retl_o2_plus_o5_plus_16)
+       add     %o5, 16, %o5
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_16)
+ENTRY(NG4_retl_o2_plus_o5_plus_24)
+       add     %o5, 24, %o5
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_24)
+ENTRY(NG4_retl_o2_plus_o5_plus_32)
+       add     %o5, 32, %o5
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o5, %o0
+ENDPROC(NG4_retl_o2_plus_o5_plus_32)
+ENTRY(NG4_retl_o2_plus_g1)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %g1, %o0
+ENDPROC(NG4_retl_o2_plus_g1)
+ENTRY(NG4_retl_o2_plus_g1_plus_1)
+       add     %g1, 1, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %g1, %o0
+ENDPROC(NG4_retl_o2_plus_g1_plus_1)
+ENTRY(NG4_retl_o2_plus_g1_plus_8)
+       add     %g1, 8, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %g1, %o0
+ENDPROC(NG4_retl_o2_plus_g1_plus_8)
+ENTRY(NG4_retl_o2_plus_o4)
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4)
+ENTRY(NG4_retl_o2_plus_o4_plus_8)
+       add     %o4, 8, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_8)
+ENTRY(NG4_retl_o2_plus_o4_plus_16)
+       add     %o4, 16, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_16)
+ENTRY(NG4_retl_o2_plus_o4_plus_24)
+       add     %o4, 24, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_24)
+ENTRY(NG4_retl_o2_plus_o4_plus_32)
+       add     %o4, 32, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_32)
+ENTRY(NG4_retl_o2_plus_o4_plus_40)
+       add     %o4, 40, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_40)
+ENTRY(NG4_retl_o2_plus_o4_plus_48)
+       add     %o4, 48, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_48)
+ENTRY(NG4_retl_o2_plus_o4_plus_56)
+       add     %o4, 56, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_56)
+ENTRY(NG4_retl_o2_plus_o4_plus_64)
+       add     %o4, 64, %o4
+       ba,pt   %xcc, __restore_asi
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_64)
+ENTRY(NG4_retl_o2_plus_o4_fp)
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_8_fp)
+       add     %o4, 8, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_8_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_16_fp)
+       add     %o4, 16, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_16_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_24_fp)
+       add     %o4, 24, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_24_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_32_fp)
+       add     %o4, 32, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_32_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_40_fp)
+       add     %o4, 40, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_40_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_48_fp)
+       add     %o4, 48, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_48_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_56_fp)
+       add     %o4, 56, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_56_fp)
+ENTRY(NG4_retl_o2_plus_o4_plus_64_fp)
+       add     %o4, 64, %o4
+       ba,pt   %xcc, __restore_asi_fp
+        add    %o2, %o4, %o0
+ENDPROC(NG4_retl_o2_plus_o4_plus_64_fp)
+#endif
        .align          64
 
        .globl  FUNC_NAME
@@ -124,12 +274,13 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        brz,pt          %g1, 51f
         sub            %o2, %g1, %o2
 
-1:     EX_LD(LOAD(ldub, %o1 + 0x00, %g2))
+
+1:     EX_LD(LOAD(ldub, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
        add             %o1, 1, %o1
        subcc           %g1, 1, %g1
        add             %o0, 1, %o0
        bne,pt          %icc, 1b
-        EX_ST(STORE(stb, %g2, %o0 - 0x01))
+        EX_ST(STORE(stb, %g2, %o0 - 0x01), NG4_retl_o2_plus_g1_plus_1)
 
 51:    LOAD(prefetch, %o1 + 0x040, #n_reads_strong)
        LOAD(prefetch, %o1 + 0x080, #n_reads_strong)
@@ -154,43 +305,43 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        brz,pt          %g1, .Llarge_aligned
         sub            %o2, %g1, %o2
 
-1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g2))
+1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
        add             %o1, 8, %o1
        subcc           %g1, 8, %g1
        add             %o0, 8, %o0
        bne,pt          %icc, 1b
-        EX_ST(STORE(stx, %g2, %o0 - 0x08))
+        EX_ST(STORE(stx, %g2, %o0 - 0x08), NG4_retl_o2_plus_g1_plus_8)
 
 .Llarge_aligned:
        /* len >= 0x80 && src 8-byte aligned && dest 8-byte aligned */
        andn            %o2, 0x3f, %o4
        sub             %o2, %o4, %o2
 
-1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g1))
+1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o4)
        add             %o1, 0x40, %o1
-       EX_LD(LOAD(ldx, %o1 - 0x38, %g2))
+       EX_LD(LOAD(ldx, %o1 - 0x38, %g2), NG4_retl_o2_plus_o4)
        subcc           %o4, 0x40, %o4
-       EX_LD(LOAD(ldx, %o1 - 0x30, %g3))
-       EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE))
-       EX_LD(LOAD(ldx, %o1 - 0x20, %o5))
-       EX_ST(STORE_INIT(%g1, %o0))
+       EX_LD(LOAD(ldx, %o1 - 0x30, %g3), NG4_retl_o2_plus_o4_plus_64)
+       EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE), NG4_retl_o2_plus_o4_plus_64)
+       EX_LD(LOAD(ldx, %o1 - 0x20, %o5), NG4_retl_o2_plus_o4_plus_64)
+       EX_ST(STORE_INIT(%g1, %o0), NG4_retl_o2_plus_o4_plus_64)
        add             %o0, 0x08, %o0
-       EX_ST(STORE_INIT(%g2, %o0))
+       EX_ST(STORE_INIT(%g2, %o0), NG4_retl_o2_plus_o4_plus_56)
        add             %o0, 0x08, %o0
-       EX_LD(LOAD(ldx, %o1 - 0x18, %g2))
-       EX_ST(STORE_INIT(%g3, %o0))
+       EX_LD(LOAD(ldx, %o1 - 0x18, %g2), NG4_retl_o2_plus_o4_plus_48)
+       EX_ST(STORE_INIT(%g3, %o0), NG4_retl_o2_plus_o4_plus_48)
        add             %o0, 0x08, %o0
-       EX_LD(LOAD(ldx, %o1 - 0x10, %g3))
-       EX_ST(STORE_INIT(GLOBAL_SPARE, %o0))
+       EX_LD(LOAD(ldx, %o1 - 0x10, %g3), NG4_retl_o2_plus_o4_plus_40)
+       EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), NG4_retl_o2_plus_o4_plus_40)
        add             %o0, 0x08, %o0
-       EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE))
-       EX_ST(STORE_INIT(%o5, %o0))
+       EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE), NG4_retl_o2_plus_o4_plus_32)
+       EX_ST(STORE_INIT(%o5, %o0), NG4_retl_o2_plus_o4_plus_32)
        add             %o0, 0x08, %o0
-       EX_ST(STORE_INIT(%g2, %o0))
+       EX_ST(STORE_INIT(%g2, %o0), NG4_retl_o2_plus_o4_plus_24)
        add             %o0, 0x08, %o0
-       EX_ST(STORE_INIT(%g3, %o0))
+       EX_ST(STORE_INIT(%g3, %o0), NG4_retl_o2_plus_o4_plus_16)
        add             %o0, 0x08, %o0
-       EX_ST(STORE_INIT(GLOBAL_SPARE, %o0))
+       EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), NG4_retl_o2_plus_o4_plus_8)
        add             %o0, 0x08, %o0
        bne,pt          %icc, 1b
         LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
@@ -216,17 +367,17 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        sub             %o2, %o4, %o2
        alignaddr       %o1, %g0, %g1
        add             %o1, %o4, %o1
-       EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0))
-1:     EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0), NG4_retl_o2_plus_o4)
+1:     EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2), NG4_retl_o2_plus_o4)
        subcc           %o4, 0x40, %o4
-       EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4))
-       EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6))
-       EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8))
-       EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10))
-       EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12))
-       EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4), NG4_retl_o2_plus_o4_plus_64)
+       EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6), NG4_retl_o2_plus_o4_plus_64)
+       EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8), NG4_retl_o2_plus_o4_plus_64)
+       EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10), NG4_retl_o2_plus_o4_plus_64)
+       EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12), NG4_retl_o2_plus_o4_plus_64)
+       EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14), NG4_retl_o2_plus_o4_plus_64)
        faligndata      %f0, %f2, %f16
-       EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0))
+       EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0), NG4_retl_o2_plus_o4_plus_64)
        faligndata      %f2, %f4, %f18
        add             %g1, 0x40, %g1
        faligndata      %f4, %f6, %f20
@@ -235,14 +386,14 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        faligndata      %f10, %f12, %f26
        faligndata      %f12, %f14, %f28
        faligndata      %f14, %f0, %f30
-       EX_ST_FP(STORE(std, %f16, %o0 + 0x00))
-       EX_ST_FP(STORE(std, %f18, %o0 + 0x08))
-       EX_ST_FP(STORE(std, %f20, %o0 + 0x10))
-       EX_ST_FP(STORE(std, %f22, %o0 + 0x18))
-       EX_ST_FP(STORE(std, %f24, %o0 + 0x20))
-       EX_ST_FP(STORE(std, %f26, %o0 + 0x28))
-       EX_ST_FP(STORE(std, %f28, %o0 + 0x30))
-       EX_ST_FP(STORE(std, %f30, %o0 + 0x38))
+       EX_ST_FP(STORE(std, %f16, %o0 + 0x00), NG4_retl_o2_plus_o4_plus_64)
+       EX_ST_FP(STORE(std, %f18, %o0 + 0x08), NG4_retl_o2_plus_o4_plus_56)
+       EX_ST_FP(STORE(std, %f20, %o0 + 0x10), NG4_retl_o2_plus_o4_plus_48)
+       EX_ST_FP(STORE(std, %f22, %o0 + 0x18), NG4_retl_o2_plus_o4_plus_40)
+       EX_ST_FP(STORE(std, %f24, %o0 + 0x20), NG4_retl_o2_plus_o4_plus_32)
+       EX_ST_FP(STORE(std, %f26, %o0 + 0x28), NG4_retl_o2_plus_o4_plus_24)
+       EX_ST_FP(STORE(std, %f28, %o0 + 0x30), NG4_retl_o2_plus_o4_plus_16)
+       EX_ST_FP(STORE(std, %f30, %o0 + 0x38), NG4_retl_o2_plus_o4_plus_8)
        add             %o0, 0x40, %o0
        bne,pt          %icc, 1b
         LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
@@ -270,37 +421,38 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        andncc          %o2, 0x20 - 1, %o5
        be,pn           %icc, 2f
         sub            %o2, %o5, %o2
-1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g1))
-       EX_LD(LOAD(ldx, %o1 + 0x08, %g2))
-       EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE))
-       EX_LD(LOAD(ldx, %o1 + 0x18, %o4))
+1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
+       EX_LD(LOAD(ldx, %o1 + 0x08, %g2), NG4_retl_o2_plus_o5)
+       EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE), NG4_retl_o2_plus_o5)
+       EX_LD(LOAD(ldx, %o1 + 0x18, %o4), NG4_retl_o2_plus_o5)
        add             %o1, 0x20, %o1
        subcc           %o5, 0x20, %o5
-       EX_ST(STORE(stx, %g1, %o0 + 0x00))
-       EX_ST(STORE(stx, %g2, %o0 + 0x08))
-       EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10))
-       EX_ST(STORE(stx, %o4, %o0 + 0x18))
+       EX_ST(STORE(stx, %g1, %o0 + 0x00), NG4_retl_o2_plus_o5_plus_32)
+       EX_ST(STORE(stx, %g2, %o0 + 0x08), NG4_retl_o2_plus_o5_plus_24)
+       EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), NG4_retl_o2_plus_o5_plus_24)
+       EX_ST(STORE(stx, %o4, %o0 + 0x18), NG4_retl_o2_plus_o5_plus_8)
        bne,pt          %icc, 1b
         add            %o0, 0x20, %o0
 2:     andcc           %o2, 0x18, %o5
        be,pt           %icc, 3f
         sub            %o2, %o5, %o2
-1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g1))
+
+1:     EX_LD(LOAD(ldx, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
        add             %o1, 0x08, %o1
        add             %o0, 0x08, %o0
        subcc           %o5, 0x08, %o5
        bne,pt          %icc, 1b
-        EX_ST(STORE(stx, %g1, %o0 - 0x08))
+        EX_ST(STORE(stx, %g1, %o0 - 0x08), NG4_retl_o2_plus_o5_plus_8)
 3:     brz,pt          %o2, .Lexit
         cmp            %o2, 0x04
        bl,pn           %icc, .Ltiny
         nop
-       EX_LD(LOAD(lduw, %o1 + 0x00, %g1))
+       EX_LD(LOAD(lduw, %o1 + 0x00, %g1), NG4_retl_o2)
        add             %o1, 0x04, %o1
        add             %o0, 0x04, %o0
        subcc           %o2, 0x04, %o2
        bne,pn          %icc, .Ltiny
-        EX_ST(STORE(stw, %g1, %o0 - 0x04))
+        EX_ST(STORE(stw, %g1, %o0 - 0x04), NG4_retl_o2_plus_4)
        ba,a,pt         %icc, .Lexit
 .Lmedium_unaligned:
        /* First get dest 8 byte aligned.  */
@@ -309,12 +461,12 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        brz,pt          %g1, 2f
         sub            %o2, %g1, %o2
 
-1:     EX_LD(LOAD(ldub, %o1 + 0x00, %g2))
+1:     EX_LD(LOAD(ldub, %o1 + 0x00, %g2), NG4_retl_o2_plus_g1)
        add             %o1, 1, %o1
        subcc           %g1, 1, %g1
        add             %o0, 1, %o0
        bne,pt          %icc, 1b
-        EX_ST(STORE(stb, %g2, %o0 - 0x01))
+        EX_ST(STORE(stb, %g2, %o0 - 0x01), NG4_retl_o2_plus_g1_plus_1)
 2:
        and             %o1, 0x7, %g1
        brz,pn          %g1, .Lmedium_noprefetch
@@ -322,16 +474,16 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        mov             64, %g2
        sub             %g2, %g1, %g2
        andn            %o1, 0x7, %o1
-       EX_LD(LOAD(ldx, %o1 + 0x00, %o4))
+       EX_LD(LOAD(ldx, %o1 + 0x00, %o4), NG4_retl_o2)
        sllx            %o4, %g1, %o4
        andn            %o2, 0x08 - 1, %o5
        sub             %o2, %o5, %o2
-1:     EX_LD(LOAD(ldx, %o1 + 0x08, %g3))
+1:     EX_LD(LOAD(ldx, %o1 + 0x08, %g3), NG4_retl_o2_plus_o5)
        add             %o1, 0x08, %o1
        subcc           %o5, 0x08, %o5
        srlx            %g3, %g2, GLOBAL_SPARE
        or              GLOBAL_SPARE, %o4, GLOBAL_SPARE
-       EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00))
+       EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00), NG4_retl_o2_plus_o5_plus_8)
        add             %o0, 0x08, %o0
        bne,pt          %icc, 1b
         sllx           %g3, %g1, %o4
@@ -342,17 +494,17 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        ba,pt           %icc, .Lsmall_unaligned
 
 .Ltiny:
-       EX_LD(LOAD(ldub, %o1 + 0x00, %g1))
+       EX_LD(LOAD(ldub, %o1 + 0x00, %g1), NG4_retl_o2)
        subcc           %o2, 1, %o2
        be,pn           %icc, .Lexit
-        EX_ST(STORE(stb, %g1, %o0 + 0x00))
-       EX_LD(LOAD(ldub, %o1 + 0x01, %g1))
+        EX_ST(STORE(stb, %g1, %o0 + 0x00), NG4_retl_o2_plus_1)
+       EX_LD(LOAD(ldub, %o1 + 0x01, %g1), NG4_retl_o2)
        subcc           %o2, 1, %o2
        be,pn           %icc, .Lexit
-        EX_ST(STORE(stb, %g1, %o0 + 0x01))
-       EX_LD(LOAD(ldub, %o1 + 0x02, %g1))
+        EX_ST(STORE(stb, %g1, %o0 + 0x01), NG4_retl_o2_plus_1)
+       EX_LD(LOAD(ldub, %o1 + 0x02, %g1), NG4_retl_o2)
        ba,pt           %icc, .Lexit
-        EX_ST(STORE(stb, %g1, %o0 + 0x02))
+        EX_ST(STORE(stb, %g1, %o0 + 0x02), NG4_retl_o2)
 
 .Lsmall:
        andcc           %g2, 0x3, %g0
@@ -360,22 +512,22 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
         andn           %o2, 0x4 - 1, %o5
        sub             %o2, %o5, %o2
 1:
-       EX_LD(LOAD(lduw, %o1 + 0x00, %g1))
+       EX_LD(LOAD(lduw, %o1 + 0x00, %g1), NG4_retl_o2_plus_o5)
        add             %o1, 0x04, %o1
        subcc           %o5, 0x04, %o5
        add             %o0, 0x04, %o0
        bne,pt          %icc, 1b
-        EX_ST(STORE(stw, %g1, %o0 - 0x04))
+        EX_ST(STORE(stw, %g1, %o0 - 0x04), NG4_retl_o2_plus_o5_plus_4)
        brz,pt          %o2, .Lexit
         nop
        ba,a,pt         %icc, .Ltiny
 
 .Lsmall_unaligned:
-1:     EX_LD(LOAD(ldub, %o1 + 0x00, %g1))
+1:     EX_LD(LOAD(ldub, %o1 + 0x00, %g1), NG4_retl_o2)
        add             %o1, 1, %o1
        add             %o0, 1, %o0
        subcc           %o2, 1, %o2
        bne,pt          %icc, 1b
-        EX_ST(STORE(stb, %g1, %o0 - 0x01))
+        EX_ST(STORE(stb, %g1, %o0 - 0x01), NG4_retl_o2_plus_1)
        ba,a,pt         %icc, .Lexit
        .size           FUNC_NAME, .-FUNC_NAME
index 5d1e4d1ac21edf09a664663dc005e1fcae805b6a..9cd42fcbc781152ca95e3c8051962ea7de1538a9 100644 (file)
@@ -3,11 +3,11 @@
  * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_LD(x)               \
+#define EX_LD(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __ret_one_asi;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
index ff630dcb273c9649de6fc9e145fce42e72667787..5c358afd464e24f3513cb6716f2983ca9f201dff 100644 (file)
@@ -3,11 +3,11 @@
  * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
  */
 
-#define EX_ST(x)               \
+#define EX_ST(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __ret_one_asi;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
index 96a14caf6966282cab2d97071f7c3837b2a6727a..d88c4ed50a0023cd8e2daa06689abc0d46d79f46 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/asi.h>
 #include <asm/thread_info.h>
 #define GLOBAL_SPARE   %g7
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)       x
+#define EX_LD(x,y)     x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)       x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)   x
+#define EX_ST(x,y)     x
 #endif
 
 #ifndef LOAD
        .register       %g3,#scratch
 
        .text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)   x
+__restore_asi:
+       ret
+       wr      %g0, ASI_AIUS, %asi
+        restore
+ENTRY(NG_ret_i2_plus_i4_plus_1)
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %i5, %i0
+ENDPROC(NG_ret_i2_plus_i4_plus_1)
+ENTRY(NG_ret_i2_plus_g1)
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1)
+ENTRY(NG_ret_i2_plus_g1_minus_8)
+       sub     %g1, 8, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_8)
+ENTRY(NG_ret_i2_plus_g1_minus_16)
+       sub     %g1, 16, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_16)
+ENTRY(NG_ret_i2_plus_g1_minus_24)
+       sub     %g1, 24, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_24)
+ENTRY(NG_ret_i2_plus_g1_minus_32)
+       sub     %g1, 32, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_32)
+ENTRY(NG_ret_i2_plus_g1_minus_40)
+       sub     %g1, 40, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_40)
+ENTRY(NG_ret_i2_plus_g1_minus_48)
+       sub     %g1, 48, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_48)
+ENTRY(NG_ret_i2_plus_g1_minus_56)
+       sub     %g1, 56, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_minus_56)
+ENTRY(NG_ret_i2_plus_i4)
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %i4, %i0
+ENDPROC(NG_ret_i2_plus_i4)
+ENTRY(NG_ret_i2_plus_i4_minus_8)
+       sub     %i4, 8, %i4
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %i4, %i0
+ENDPROC(NG_ret_i2_plus_i4_minus_8)
+ENTRY(NG_ret_i2_plus_8)
+       ba,pt   %xcc, __restore_asi
+        add    %i2, 8, %i0
+ENDPROC(NG_ret_i2_plus_8)
+ENTRY(NG_ret_i2_plus_4)
+       ba,pt   %xcc, __restore_asi
+        add    %i2, 4, %i0
+ENDPROC(NG_ret_i2_plus_4)
+ENTRY(NG_ret_i2_plus_1)
+       ba,pt   %xcc, __restore_asi
+        add    %i2, 1, %i0
+ENDPROC(NG_ret_i2_plus_1)
+ENTRY(NG_ret_i2_plus_g1_plus_1)
+       add     %g1, 1, %g1
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %g1, %i0
+ENDPROC(NG_ret_i2_plus_g1_plus_1)
+ENTRY(NG_ret_i2)
+       ba,pt   %xcc, __restore_asi
+        mov    %i2, %i0
+ENDPROC(NG_ret_i2)
+ENTRY(NG_ret_i2_and_7_plus_i4)
+       and     %i2, 7, %i2
+       ba,pt   %xcc, __restore_asi
+        add    %i2, %i4, %i0
+ENDPROC(NG_ret_i2_and_7_plus_i4)
+#endif
+
        .align          64
 
        .globl  FUNC_NAME
@@ -126,8 +209,8 @@ FUNC_NAME:  /* %i0=dst, %i1=src, %i2=len */
        sub             %g0, %i4, %i4   ! bytes to align dst
        sub             %i2, %i4, %i2
 1:     subcc           %i4, 1, %i4
-       EX_LD(LOAD(ldub, %i1, %g1))
-       EX_ST(STORE(stb, %g1, %o0))
+       EX_LD(LOAD(ldub, %i1, %g1), NG_ret_i2_plus_i4_plus_1)
+       EX_ST(STORE(stb, %g1, %o0), NG_ret_i2_plus_i4_plus_1)
        add             %i1, 1, %i1
        bne,pt          %XCC, 1b
        add             %o0, 1, %o0
@@ -160,7 +243,7 @@ FUNC_NAME:  /* %i0=dst, %i1=src, %i2=len */
        and             %i4, 0x7, GLOBAL_SPARE
        sll             GLOBAL_SPARE, 3, GLOBAL_SPARE
        mov             64, %i5
-       EX_LD(LOAD_TWIN(%i1, %g2, %g3))
+       EX_LD(LOAD_TWIN(%i1, %g2, %g3), NG_ret_i2_plus_g1)
        sub             %i5, GLOBAL_SPARE, %i5
        mov             16, %o4
        mov             32, %o5
@@ -178,31 +261,31 @@ FUNC_NAME:        /* %i0=dst, %i1=src, %i2=len */
        srlx            WORD3, PRE_SHIFT, TMP; \
        or              WORD2, TMP, WORD2;
 
-8:     EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3))
+8:     EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3), NG_ret_i2_plus_g1)
        MIX_THREE_WORDS(%g2, %g3, %o2, %i5, GLOBAL_SPARE, %o1)
        LOAD(prefetch, %i1 + %i3, #one_read)
 
-       EX_ST(STORE_INIT(%g2, %o0 + 0x00))
-       EX_ST(STORE_INIT(%g3, %o0 + 0x08))
+       EX_ST(STORE_INIT(%g2, %o0 + 0x00), NG_ret_i2_plus_g1)
+       EX_ST(STORE_INIT(%g3, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
 
-       EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3))
+       EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3), NG_ret_i2_plus_g1_minus_16)
        MIX_THREE_WORDS(%o2, %o3, %g2, %i5, GLOBAL_SPARE, %o1)
 
-       EX_ST(STORE_INIT(%o2, %o0 + 0x10))
-       EX_ST(STORE_INIT(%o3, %o0 + 0x18))
+       EX_ST(STORE_INIT(%o2, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+       EX_ST(STORE_INIT(%o3, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
 
-       EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+       EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
        MIX_THREE_WORDS(%g2, %g3, %o2, %i5, GLOBAL_SPARE, %o1)
 
-       EX_ST(STORE_INIT(%g2, %o0 + 0x20))
-       EX_ST(STORE_INIT(%g3, %o0 + 0x28))
+       EX_ST(STORE_INIT(%g2, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+       EX_ST(STORE_INIT(%g3, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
 
-       EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3))
+       EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3), NG_ret_i2_plus_g1_minus_48)
        add             %i1, 64, %i1
        MIX_THREE_WORDS(%o2, %o3, %g2, %i5, GLOBAL_SPARE, %o1)
 
-       EX_ST(STORE_INIT(%o2, %o0 + 0x30))
-       EX_ST(STORE_INIT(%o3, %o0 + 0x38))
+       EX_ST(STORE_INIT(%o2, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+       EX_ST(STORE_INIT(%o3, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
 
        subcc           %g1, 64, %g1
        bne,pt          %XCC, 8b
@@ -211,31 +294,31 @@ FUNC_NAME:        /* %i0=dst, %i1=src, %i2=len */
        ba,pt           %XCC, 60f
         add            %i1, %i4, %i1
 
-9:     EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3))
+9:     EX_LD(LOAD_TWIN(%i1 + %o4, %o2, %o3), NG_ret_i2_plus_g1)
        MIX_THREE_WORDS(%g3, %o2, %o3, %i5, GLOBAL_SPARE, %o1)
        LOAD(prefetch, %i1 + %i3, #one_read)
 
-       EX_ST(STORE_INIT(%g3, %o0 + 0x00))
-       EX_ST(STORE_INIT(%o2, %o0 + 0x08))
+       EX_ST(STORE_INIT(%g3, %o0 + 0x00), NG_ret_i2_plus_g1)
+       EX_ST(STORE_INIT(%o2, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
 
-       EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3))
+       EX_LD(LOAD_TWIN(%i1 + %o5, %g2, %g3), NG_ret_i2_plus_g1_minus_16)
        MIX_THREE_WORDS(%o3, %g2, %g3, %i5, GLOBAL_SPARE, %o1)
 
-       EX_ST(STORE_INIT(%o3, %o0 + 0x10))
-       EX_ST(STORE_INIT(%g2, %o0 + 0x18))
+       EX_ST(STORE_INIT(%o3, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+       EX_ST(STORE_INIT(%g2, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
 
-       EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+       EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
        MIX_THREE_WORDS(%g3, %o2, %o3, %i5, GLOBAL_SPARE, %o1)
 
-       EX_ST(STORE_INIT(%g3, %o0 + 0x20))
-       EX_ST(STORE_INIT(%o2, %o0 + 0x28))
+       EX_ST(STORE_INIT(%g3, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+       EX_ST(STORE_INIT(%o2, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
 
-       EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3))
+       EX_LD(LOAD_TWIN(%i1 + %i3, %g2, %g3), NG_ret_i2_plus_g1_minus_48)
        add             %i1, 64, %i1
        MIX_THREE_WORDS(%o3, %g2, %g3, %i5, GLOBAL_SPARE, %o1)
 
-       EX_ST(STORE_INIT(%o3, %o0 + 0x30))
-       EX_ST(STORE_INIT(%g2, %o0 + 0x38))
+       EX_ST(STORE_INIT(%o3, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+       EX_ST(STORE_INIT(%g2, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
 
        subcc           %g1, 64, %g1
        bne,pt          %XCC, 9b
@@ -249,25 +332,25 @@ FUNC_NAME:        /* %i0=dst, %i1=src, %i2=len */
         * one twin load ahead, then add 8 back into source when
         * we finish the loop.
         */
-       EX_LD(LOAD_TWIN(%i1, %o4, %o5))
+       EX_LD(LOAD_TWIN(%i1, %o4, %o5), NG_ret_i2_plus_g1)
        mov     16, %o7
        mov     32, %g2
        mov     48, %g3
        mov     64, %o1
-1:     EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+1:     EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1)
        LOAD(prefetch, %i1 + %o1, #one_read)
-       EX_ST(STORE_INIT(%o5, %o0 + 0x00))      ! initializes cache line
-       EX_ST(STORE_INIT(%o2, %o0 + 0x08))
-       EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5))
-       EX_ST(STORE_INIT(%o3, %o0 + 0x10))
-       EX_ST(STORE_INIT(%o4, %o0 + 0x18))
-       EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3))
-       EX_ST(STORE_INIT(%o5, %o0 + 0x20))
-       EX_ST(STORE_INIT(%o2, %o0 + 0x28))
-       EX_LD(LOAD_TWIN(%i1 + %o1, %o4, %o5))
+       EX_ST(STORE_INIT(%o5, %o0 + 0x00), NG_ret_i2_plus_g1)   ! initializes cache line
+       EX_ST(STORE_INIT(%o2, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
+       EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5), NG_ret_i2_plus_g1_minus_16)
+       EX_ST(STORE_INIT(%o3, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+       EX_ST(STORE_INIT(%o4, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
+       EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
+       EX_ST(STORE_INIT(%o5, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+       EX_ST(STORE_INIT(%o2, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
+       EX_LD(LOAD_TWIN(%i1 + %o1, %o4, %o5), NG_ret_i2_plus_g1_minus_48)
        add             %i1, 64, %i1
-       EX_ST(STORE_INIT(%o3, %o0 + 0x30))
-       EX_ST(STORE_INIT(%o4, %o0 + 0x38))
+       EX_ST(STORE_INIT(%o3, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+       EX_ST(STORE_INIT(%o4, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
        subcc           %g1, 64, %g1
        bne,pt          %XCC, 1b
         add            %o0, 64, %o0
@@ -282,20 +365,20 @@ FUNC_NAME:        /* %i0=dst, %i1=src, %i2=len */
        mov     32, %g2
        mov     48, %g3
        mov     64, %o1
-1:     EX_LD(LOAD_TWIN(%i1 + %g0, %o4, %o5))
-       EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3))
+1:     EX_LD(LOAD_TWIN(%i1 + %g0, %o4, %o5), NG_ret_i2_plus_g1)
+       EX_LD(LOAD_TWIN(%i1 + %o7, %o2, %o3), NG_ret_i2_plus_g1)
        LOAD(prefetch, %i1 + %o1, #one_read)
-       EX_ST(STORE_INIT(%o4, %o0 + 0x00))      ! initializes cache line
-       EX_ST(STORE_INIT(%o5, %o0 + 0x08))
-       EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5))
-       EX_ST(STORE_INIT(%o2, %o0 + 0x10))
-       EX_ST(STORE_INIT(%o3, %o0 + 0x18))
-       EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3))
+       EX_ST(STORE_INIT(%o4, %o0 + 0x00), NG_ret_i2_plus_g1)   ! initializes cache line
+       EX_ST(STORE_INIT(%o5, %o0 + 0x08), NG_ret_i2_plus_g1_minus_8)
+       EX_LD(LOAD_TWIN(%i1 + %g2, %o4, %o5), NG_ret_i2_plus_g1_minus_16)
+       EX_ST(STORE_INIT(%o2, %o0 + 0x10), NG_ret_i2_plus_g1_minus_16)
+       EX_ST(STORE_INIT(%o3, %o0 + 0x18), NG_ret_i2_plus_g1_minus_24)
+       EX_LD(LOAD_TWIN(%i1 + %g3, %o2, %o3), NG_ret_i2_plus_g1_minus_32)
        add     %i1, 64, %i1
-       EX_ST(STORE_INIT(%o4, %o0 + 0x20))
-       EX_ST(STORE_INIT(%o5, %o0 + 0x28))
-       EX_ST(STORE_INIT(%o2, %o0 + 0x30))
-       EX_ST(STORE_INIT(%o3, %o0 + 0x38))
+       EX_ST(STORE_INIT(%o4, %o0 + 0x20), NG_ret_i2_plus_g1_minus_32)
+       EX_ST(STORE_INIT(%o5, %o0 + 0x28), NG_ret_i2_plus_g1_minus_40)
+       EX_ST(STORE_INIT(%o2, %o0 + 0x30), NG_ret_i2_plus_g1_minus_48)
+       EX_ST(STORE_INIT(%o3, %o0 + 0x38), NG_ret_i2_plus_g1_minus_56)
        subcc   %g1, 64, %g1
        bne,pt  %XCC, 1b
         add    %o0, 64, %o0
@@ -321,28 +404,28 @@ FUNC_NAME:        /* %i0=dst, %i1=src, %i2=len */
        andn            %i2, 0xf, %i4
        and             %i2, 0xf, %i2
 1:     subcc           %i4, 0x10, %i4
-       EX_LD(LOAD(ldx, %i1, %o4))
+       EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_i4)
        add             %i1, 0x08, %i1
-       EX_LD(LOAD(ldx, %i1, %g1))
+       EX_LD(LOAD(ldx, %i1, %g1), NG_ret_i2_plus_i4)
        sub             %i1, 0x08, %i1
-       EX_ST(STORE(stx, %o4, %i1 + %i3))
+       EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_i4)
        add             %i1, 0x8, %i1
-       EX_ST(STORE(stx, %g1, %i1 + %i3))
+       EX_ST(STORE(stx, %g1, %i1 + %i3), NG_ret_i2_plus_i4_minus_8)
        bgu,pt          %XCC, 1b
         add            %i1, 0x8, %i1
 73:    andcc           %i2, 0x8, %g0
        be,pt           %XCC, 1f
         nop
        sub             %i2, 0x8, %i2
-       EX_LD(LOAD(ldx, %i1, %o4))
-       EX_ST(STORE(stx, %o4, %i1 + %i3))
+       EX_LD(LOAD(ldx, %i1, %o4), NG_ret_i2_plus_8)
+       EX_ST(STORE(stx, %o4, %i1 + %i3), NG_ret_i2_plus_8)
        add             %i1, 0x8, %i1
 1:     andcc           %i2, 0x4, %g0
        be,pt           %XCC, 1f
         nop
        sub             %i2, 0x4, %i2
-       EX_LD(LOAD(lduw, %i1, %i5))
-       EX_ST(STORE(stw, %i5, %i1 + %i3))
+       EX_LD(LOAD(lduw, %i1, %i5), NG_ret_i2_plus_4)
+       EX_ST(STORE(stw, %i5, %i1 + %i3), NG_ret_i2_plus_4)
        add             %i1, 0x4, %i1
 1:     cmp             %i2, 0
        be,pt           %XCC, 85f
@@ -358,8 +441,8 @@ FUNC_NAME:  /* %i0=dst, %i1=src, %i2=len */
        sub             %i2, %g1, %i2
 
 1:     subcc           %g1, 1, %g1
-       EX_LD(LOAD(ldub, %i1, %i5))
-       EX_ST(STORE(stb, %i5, %i1 + %i3))
+       EX_LD(LOAD(ldub, %i1, %i5), NG_ret_i2_plus_g1_plus_1)
+       EX_ST(STORE(stb, %i5, %i1 + %i3), NG_ret_i2_plus_g1_plus_1)
        bgu,pt          %icc, 1b
         add            %i1, 1, %i1
 
@@ -375,16 +458,16 @@ FUNC_NAME:        /* %i0=dst, %i1=src, %i2=len */
 
 8:     mov             64, %i3
        andn            %i1, 0x7, %i1
-       EX_LD(LOAD(ldx, %i1, %g2))
+       EX_LD(LOAD(ldx, %i1, %g2), NG_ret_i2)
        sub             %i3, %g1, %i3
        andn            %i2, 0x7, %i4
        sllx            %g2, %g1, %g2
 1:     add             %i1, 0x8, %i1
-       EX_LD(LOAD(ldx, %i1, %g3))
+       EX_LD(LOAD(ldx, %i1, %g3), NG_ret_i2_and_7_plus_i4)
        subcc           %i4, 0x8, %i4
        srlx            %g3, %i3, %i5
        or              %i5, %g2, %i5
-       EX_ST(STORE(stx, %i5, %o0))
+       EX_ST(STORE(stx, %i5, %o0), NG_ret_i2_and_7_plus_i4)
        add             %o0, 0x8, %o0
        bgu,pt          %icc, 1b
         sllx           %g3, %g1, %g2
@@ -404,8 +487,8 @@ FUNC_NAME:  /* %i0=dst, %i1=src, %i2=len */
 
 1:
        subcc           %i2, 4, %i2
-       EX_LD(LOAD(lduw, %i1, %g1))
-       EX_ST(STORE(stw, %g1, %i1 + %i3))
+       EX_LD(LOAD(lduw, %i1, %g1), NG_ret_i2_plus_4)
+       EX_ST(STORE(stw, %g1, %i1 + %i3), NG_ret_i2_plus_4)
        bgu,pt          %XCC, 1b
         add            %i1, 4, %i1
 
@@ -415,8 +498,8 @@ FUNC_NAME:  /* %i0=dst, %i1=src, %i2=len */
        .align          32
 90:
        subcc           %i2, 1, %i2
-       EX_LD(LOAD(ldub, %i1, %g1))
-       EX_ST(STORE(stb, %g1, %i1 + %i3))
+       EX_LD(LOAD(ldub, %i1, %g1), NG_ret_i2_plus_1)
+       EX_ST(STORE(stb, %g1, %i1 + %i3), NG_ret_i2_plus_1)
        bgu,pt          %XCC, 90b
         add            %i1, 1, %i1
        ret
index ecc5692fa2b49a3acfc6a6592c6c247835417b4c..bb6ff73229e3e5e7eac225389db53c27d989abc1 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_LD(x)               \
+#define EX_LD(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one;  \
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_LD_FP(x)            \
+#define EX_LD_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_fp;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
index 9eea392e44d471679ba85c22867a9767b34912a5..ed92ce73955889dba9faa8f028b7e5e6c4326ecf 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_ST(x)               \
+#define EX_ST(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one;  \
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_ST_FP(x)            \
+#define EX_ST_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_fp;\
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
index 97e1b211090c2ac50a5194b418b091ff9e10f95d..4f0d50b33a72482e98411a2bd1b891de7229089d 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #include <asm/export.h>
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)       x
+#define EX_LD(x,y)     x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)    x
+#define EX_LD_FP(x,y)  x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)       x
+#define EX_ST(x,y)     x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)    x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)   x
+#define EX_ST_FP(x,y)  x
 #endif
 
 #ifndef LOAD
        faligndata              %f7, %f8, %f60;                 \
        faligndata              %f8, %f9, %f62;
 
-#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt)   \
-       EX_LD_FP(LOAD_BLK(%src, %fdest));                               \
-       EX_ST_FP(STORE_BLK(%fsrc, %dest));                              \
-       add                     %src, 0x40, %src;               \
-       subcc                   %len, 0x40, %len;               \
-       be,pn                   %xcc, jmptgt;                   \
-        add                    %dest, 0x40, %dest;             \
-
-#define LOOP_CHUNK1(src, dest, len, branch_dest)               \
-       MAIN_LOOP_CHUNK(src, dest, f0,  f48, len, branch_dest)
-#define LOOP_CHUNK2(src, dest, len, branch_dest)               \
-       MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest)
-#define LOOP_CHUNK3(src, dest, len, branch_dest)               \
-       MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
+#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, jmptgt)                        \
+       EX_LD_FP(LOAD_BLK(%src, %fdest), U1_gs_80_fp);                  \
+       EX_ST_FP(STORE_BLK(%fsrc, %dest), U1_gs_80_fp);                 \
+       add                     %src, 0x40, %src;                       \
+       subcc                   %GLOBAL_SPARE, 0x40, %GLOBAL_SPARE;     \
+       be,pn                   %xcc, jmptgt;                           \
+        add                    %dest, 0x40, %dest;                     \
+
+#define LOOP_CHUNK1(src, dest, branch_dest)            \
+       MAIN_LOOP_CHUNK(src, dest, f0,  f48, branch_dest)
+#define LOOP_CHUNK2(src, dest, branch_dest)            \
+       MAIN_LOOP_CHUNK(src, dest, f16, f48, branch_dest)
+#define LOOP_CHUNK3(src, dest, branch_dest)            \
+       MAIN_LOOP_CHUNK(src, dest, f32, f48, branch_dest)
 
 #define DO_SYNC                        membar  #Sync;
 #define STORE_SYNC(dest, fsrc)                         \
-       EX_ST_FP(STORE_BLK(%fsrc, %dest));                      \
+       EX_ST_FP(STORE_BLK(%fsrc, %dest), U1_gs_80_fp); \
        add                     %dest, 0x40, %dest;     \
        DO_SYNC
 
 #define STORE_JUMP(dest, fsrc, target)                 \
-       EX_ST_FP(STORE_BLK(%fsrc, %dest));                      \
+       EX_ST_FP(STORE_BLK(%fsrc, %dest), U1_gs_40_fp); \
        add                     %dest, 0x40, %dest;     \
        ba,pt                   %xcc, target;           \
         nop;
 
-#define FINISH_VISCHUNK(dest, f0, f1, left)    \
-       subcc                   %left, 8, %left;\
-       bl,pn                   %xcc, 95f;      \
-        faligndata             %f0, %f1, %f48; \
-       EX_ST_FP(STORE(std, %f48, %dest));              \
+#define FINISH_VISCHUNK(dest, f0, f1)                  \
+       subcc                   %g3, 8, %g3;            \
+       bl,pn                   %xcc, 95f;              \
+        faligndata             %f0, %f1, %f48;         \
+       EX_ST_FP(STORE(std, %f48, %dest), U1_g3_8_fp);  \
        add                     %dest, 8, %dest;
 
-#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)       \
-       subcc                   %left, 8, %left;        \
-       bl,pn                   %xcc, 95f;              \
+#define UNEVEN_VISCHUNK_LAST(dest, f0, f1)     \
+       subcc                   %g3, 8, %g3;    \
+       bl,pn                   %xcc, 95f;      \
         fsrc2                  %f0, %f1;
 
-#define UNEVEN_VISCHUNK(dest, f0, f1, left)            \
-       UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)        \
+#define UNEVEN_VISCHUNK(dest, f0, f1)          \
+       UNEVEN_VISCHUNK_LAST(dest, f0, f1)      \
        ba,a,pt                 %xcc, 93f;
 
        .register       %g2,#scratch
        .register       %g3,#scratch
 
        .text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)   x
+ENTRY(U1_g1_1_fp)
+       VISExitHalf
+       add             %g1, 1, %g1
+       add             %g1, %g2, %g1
+       retl
+        add            %g1, %o2, %o0
+ENDPROC(U1_g1_1_fp)
+ENTRY(U1_g2_0_fp)
+       VISExitHalf
+       retl
+        add            %g2, %o2, %o0
+ENDPROC(U1_g2_0_fp)
+ENTRY(U1_g2_8_fp)
+       VISExitHalf
+       add             %g2, 8, %g2
+       retl
+        add            %g2, %o2, %o0
+ENDPROC(U1_g2_8_fp)
+ENTRY(U1_gs_0_fp)
+       VISExitHalf
+       add             %GLOBAL_SPARE, %g3, %o0
+       retl
+        add            %o0, %o2, %o0
+ENDPROC(U1_gs_0_fp)
+ENTRY(U1_gs_80_fp)
+       VISExitHalf
+       add             %GLOBAL_SPARE, 0x80, %GLOBAL_SPARE
+       add             %GLOBAL_SPARE, %g3, %o0
+       retl
+        add            %o0, %o2, %o0
+ENDPROC(U1_gs_80_fp)
+ENTRY(U1_gs_40_fp)
+       VISExitHalf
+       add             %GLOBAL_SPARE, 0x40, %GLOBAL_SPARE
+       add             %GLOBAL_SPARE, %g3, %o0
+       retl
+        add            %o0, %o2, %o0
+ENDPROC(U1_gs_40_fp)
+ENTRY(U1_g3_0_fp)
+       VISExitHalf
+       retl
+        add            %g3, %o2, %o0
+ENDPROC(U1_g3_0_fp)
+ENTRY(U1_g3_8_fp)
+       VISExitHalf
+       add             %g3, 8, %g3
+       retl
+        add            %g3, %o2, %o0
+ENDPROC(U1_g3_8_fp)
+ENTRY(U1_o2_0_fp)
+       VISExitHalf
+       retl
+        mov            %o2, %o0
+ENDPROC(U1_o2_0_fp)
+ENTRY(U1_o2_1_fp)
+       VISExitHalf
+       retl
+        add            %o2, 1, %o0
+ENDPROC(U1_o2_1_fp)
+ENTRY(U1_gs_0)
+       VISExitHalf
+       retl
+        add            %GLOBAL_SPARE, %o2, %o0
+ENDPROC(U1_gs_0)
+ENTRY(U1_gs_8)
+       VISExitHalf
+       add             %GLOBAL_SPARE, %o2, %GLOBAL_SPARE
+       retl
+        add            %GLOBAL_SPARE, 0x8, %o0
+ENDPROC(U1_gs_8)
+ENTRY(U1_gs_10)
+       VISExitHalf
+       add             %GLOBAL_SPARE, %o2, %GLOBAL_SPARE
+       retl
+        add            %GLOBAL_SPARE, 0x10, %o0
+ENDPROC(U1_gs_10)
+ENTRY(U1_o2_0)
+       retl
+        mov            %o2, %o0
+ENDPROC(U1_o2_0)
+ENTRY(U1_o2_8)
+       retl
+        add            %o2, 8, %o0
+ENDPROC(U1_o2_8)
+ENTRY(U1_o2_4)
+       retl
+        add            %o2, 4, %o0
+ENDPROC(U1_o2_4)
+ENTRY(U1_o2_1)
+       retl
+        add            %o2, 1, %o0
+ENDPROC(U1_o2_1)
+ENTRY(U1_g1_0)
+       retl
+        add            %g1, %o2, %o0
+ENDPROC(U1_g1_0)
+ENTRY(U1_g1_1)
+       add             %g1, 1, %g1
+       retl
+        add            %g1, %o2, %o0
+ENDPROC(U1_g1_1)
+ENTRY(U1_gs_0_o2_adj)
+       and             %o2, 7, %o2
+       retl
+        add            %GLOBAL_SPARE, %o2, %o0
+ENDPROC(U1_gs_0_o2_adj)
+ENTRY(U1_gs_8_o2_adj)
+       and             %o2, 7, %o2
+       add             %GLOBAL_SPARE, 8, %GLOBAL_SPARE
+       retl
+        add            %GLOBAL_SPARE, %o2, %o0
+ENDPROC(U1_gs_8_o2_adj)
+#endif
+
        .align          64
 
        .globl          FUNC_NAME
@@ -167,8 +280,8 @@ FUNC_NAME:          /* %o0=dst, %o1=src, %o2=len */
         and            %g2, 0x38, %g2
 
 1:     subcc           %g1, 0x1, %g1
-       EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
-       EX_ST_FP(STORE(stb, %o3, %o1 + %GLOBAL_SPARE))
+       EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3), U1_g1_1_fp)
+       EX_ST_FP(STORE(stb, %o3, %o1 + %GLOBAL_SPARE), U1_g1_1_fp)
        bgu,pt          %XCC, 1b
         add            %o1, 0x1, %o1
 
@@ -179,20 +292,20 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        be,pt           %icc, 3f
         alignaddr      %o1, %g0, %o1
 
-       EX_LD_FP(LOAD(ldd, %o1, %f4))
-1:     EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
+       EX_LD_FP(LOAD(ldd, %o1, %f4), U1_g2_0_fp)
+1:     EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6), U1_g2_0_fp)
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f4, %f6, %f0
-       EX_ST_FP(STORE(std, %f0, %o0))
+       EX_ST_FP(STORE(std, %f0, %o0), U1_g2_8_fp)
        be,pn           %icc, 3f
         add            %o0, 0x8, %o0
 
-       EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4), U1_g2_0_fp)
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f6, %f4, %f0
-       EX_ST_FP(STORE(std, %f0, %o0))
+       EX_ST_FP(STORE(std, %f0, %o0), U1_g2_8_fp)
        bne,pt          %icc, 1b
         add            %o0, 0x8, %o0
 
@@ -215,13 +328,13 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        add             %g1, %GLOBAL_SPARE, %g1
        subcc           %o2, %g3, %o2
 
-       EX_LD_FP(LOAD_BLK(%o1, %f0))
+       EX_LD_FP(LOAD_BLK(%o1, %f0), U1_gs_0_fp)
        add             %o1, 0x40, %o1
        add             %g1, %g3, %g1
-       EX_LD_FP(LOAD_BLK(%o1, %f16))
+       EX_LD_FP(LOAD_BLK(%o1, %f16), U1_gs_0_fp)
        add             %o1, 0x40, %o1
        sub             %GLOBAL_SPARE, 0x80, %GLOBAL_SPARE
-       EX_LD_FP(LOAD_BLK(%o1, %f32))
+       EX_LD_FP(LOAD_BLK(%o1, %f32), U1_gs_80_fp)
        add             %o1, 0x40, %o1
 
        /* There are 8 instances of the unrolled loop,
@@ -241,11 +354,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
 
        .align          64
 1:     FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f0, %f2, %f48
 1:     FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
@@ -262,11 +375,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        STORE_JUMP(o0, f48, 56f)
 
 1:     FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f2, %f4, %f48
 1:     FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
@@ -283,11 +396,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        STORE_JUMP(o0, f48, 57f)
 
 1:     FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f4, %f6, %f48
 1:     FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
@@ -304,11 +417,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        STORE_JUMP(o0, f48, 58f)
 
 1:     FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) 
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f6, %f8, %f48
 1:     FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
@@ -325,11 +438,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        STORE_JUMP(o0, f48, 59f)
 
 1:     FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f8, %f10, %f48
 1:     FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
@@ -346,11 +459,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        STORE_JUMP(o0, f48, 60f)
 
 1:     FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f10, %f12, %f48
 1:     FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
@@ -367,11 +480,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        STORE_JUMP(o0, f48, 61f)
 
 1:     FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f12, %f14, %f48
 1:     FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
@@ -388,11 +501,11 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        STORE_JUMP(o0, f48, 62f)
 
 1:     FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
-       LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
+       LOOP_CHUNK1(o1, o0, 1f)
        FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
-       LOOP_CHUNK2(o1, o0, GLOBAL_SPARE, 2f)
+       LOOP_CHUNK2(o1, o0, 2f)
        FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
-       LOOP_CHUNK3(o1, o0, GLOBAL_SPARE, 3f)
+       LOOP_CHUNK3(o1, o0, 3f)
        ba,pt           %xcc, 1b+4
         faligndata     %f14, %f16, %f48
 1:     FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
@@ -408,53 +521,53 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
        FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
        STORE_JUMP(o0, f48, 63f)
 
-40:    FINISH_VISCHUNK(o0, f0,  f2,  g3)
-41:    FINISH_VISCHUNK(o0, f2,  f4,  g3)
-42:    FINISH_VISCHUNK(o0, f4,  f6,  g3)
-43:    FINISH_VISCHUNK(o0, f6,  f8,  g3)
-44:    FINISH_VISCHUNK(o0, f8,  f10, g3)
-45:    FINISH_VISCHUNK(o0, f10, f12, g3)
-46:    FINISH_VISCHUNK(o0, f12, f14, g3)
-47:    UNEVEN_VISCHUNK(o0, f14, f0,  g3)
-48:    FINISH_VISCHUNK(o0, f16, f18, g3)
-49:    FINISH_VISCHUNK(o0, f18, f20, g3)
-50:    FINISH_VISCHUNK(o0, f20, f22, g3)
-51:    FINISH_VISCHUNK(o0, f22, f24, g3)
-52:    FINISH_VISCHUNK(o0, f24, f26, g3)
-53:    FINISH_VISCHUNK(o0, f26, f28, g3)
-54:    FINISH_VISCHUNK(o0, f28, f30, g3)
-55:    UNEVEN_VISCHUNK(o0, f30, f0,  g3)
-56:    FINISH_VISCHUNK(o0, f32, f34, g3)
-57:    FINISH_VISCHUNK(o0, f34, f36, g3)
-58:    FINISH_VISCHUNK(o0, f36, f38, g3)
-59:    FINISH_VISCHUNK(o0, f38, f40, g3)
-60:    FINISH_VISCHUNK(o0, f40, f42, g3)
-61:    FINISH_VISCHUNK(o0, f42, f44, g3)
-62:    FINISH_VISCHUNK(o0, f44, f46, g3)
-63:    UNEVEN_VISCHUNK_LAST(o0, f46, f0,  g3)
-
-93:    EX_LD_FP(LOAD(ldd, %o1, %f2))
+40:    FINISH_VISCHUNK(o0, f0,  f2)
+41:    FINISH_VISCHUNK(o0, f2,  f4)
+42:    FINISH_VISCHUNK(o0, f4,  f6)
+43:    FINISH_VISCHUNK(o0, f6,  f8)
+44:    FINISH_VISCHUNK(o0, f8,  f10)
+45:    FINISH_VISCHUNK(o0, f10, f12)
+46:    FINISH_VISCHUNK(o0, f12, f14)
+47:    UNEVEN_VISCHUNK(o0, f14, f0)
+48:    FINISH_VISCHUNK(o0, f16, f18)
+49:    FINISH_VISCHUNK(o0, f18, f20)
+50:    FINISH_VISCHUNK(o0, f20, f22)
+51:    FINISH_VISCHUNK(o0, f22, f24)
+52:    FINISH_VISCHUNK(o0, f24, f26)
+53:    FINISH_VISCHUNK(o0, f26, f28)
+54:    FINISH_VISCHUNK(o0, f28, f30)
+55:    UNEVEN_VISCHUNK(o0, f30, f0)
+56:    FINISH_VISCHUNK(o0, f32, f34)
+57:    FINISH_VISCHUNK(o0, f34, f36)
+58:    FINISH_VISCHUNK(o0, f36, f38)
+59:    FINISH_VISCHUNK(o0, f38, f40)
+60:    FINISH_VISCHUNK(o0, f40, f42)
+61:    FINISH_VISCHUNK(o0, f42, f44)
+62:    FINISH_VISCHUNK(o0, f44, f46)
+63:    UNEVEN_VISCHUNK_LAST(o0, f46, f0)
+
+93:    EX_LD_FP(LOAD(ldd, %o1, %f2), U1_g3_0_fp)
        add             %o1, 8, %o1
        subcc           %g3, 8, %g3
        faligndata      %f0, %f2, %f8
-       EX_ST_FP(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0), U1_g3_8_fp)
        bl,pn           %xcc, 95f
         add            %o0, 8, %o0
-       EX_LD_FP(LOAD(ldd, %o1, %f0))
+       EX_LD_FP(LOAD(ldd, %o1, %f0), U1_g3_0_fp)
        add             %o1, 8, %o1
        subcc           %g3, 8, %g3
        faligndata      %f2, %f0, %f8
-       EX_ST_FP(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0), U1_g3_8_fp)
        bge,pt          %xcc, 93b
         add            %o0, 8, %o0
 
 95:    brz,pt          %o2, 2f
         mov            %g1, %o1
 
-1:     EX_LD_FP(LOAD(ldub, %o1, %o3))
+1:     EX_LD_FP(LOAD(ldub, %o1, %o3), U1_o2_0_fp)
        add             %o1, 1, %o1
        subcc           %o2, 1, %o2
-       EX_ST_FP(STORE(stb, %o3, %o0))
+       EX_ST_FP(STORE(stb, %o3, %o0), U1_o2_1_fp)
        bne,pt          %xcc, 1b
         add            %o0, 1, %o0
 
@@ -470,27 +583,27 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
 
 72:    andn            %o2, 0xf, %GLOBAL_SPARE
        and             %o2, 0xf, %o2
-1:     EX_LD(LOAD(ldx, %o1 + 0x00, %o5))
-       EX_LD(LOAD(ldx, %o1 + 0x08, %g1))
+1:     EX_LD(LOAD(ldx, %o1 + 0x00, %o5), U1_gs_0)
+       EX_LD(LOAD(ldx, %o1 + 0x08, %g1), U1_gs_0)
        subcc           %GLOBAL_SPARE, 0x10, %GLOBAL_SPARE
-       EX_ST(STORE(stx, %o5, %o1 + %o3))
+       EX_ST(STORE(stx, %o5, %o1 + %o3), U1_gs_10)
        add             %o1, 0x8, %o1
-       EX_ST(STORE(stx, %g1, %o1 + %o3))
+       EX_ST(STORE(stx, %g1, %o1 + %o3), U1_gs_8)
        bgu,pt          %XCC, 1b
         add            %o1, 0x8, %o1
 73:    andcc           %o2, 0x8, %g0
        be,pt           %XCC, 1f
         nop
-       EX_LD(LOAD(ldx, %o1, %o5))
+       EX_LD(LOAD(ldx, %o1, %o5), U1_o2_0)
        sub             %o2, 0x8, %o2
-       EX_ST(STORE(stx, %o5, %o1 + %o3))
+       EX_ST(STORE(stx, %o5, %o1 + %o3), U1_o2_8)
        add             %o1, 0x8, %o1
 1:     andcc           %o2, 0x4, %g0
        be,pt           %XCC, 1f
         nop
-       EX_LD(LOAD(lduw, %o1, %o5))
+       EX_LD(LOAD(lduw, %o1, %o5), U1_o2_0)
        sub             %o2, 0x4, %o2
-       EX_ST(STORE(stw, %o5, %o1 + %o3))
+       EX_ST(STORE(stw, %o5, %o1 + %o3), U1_o2_4)
        add             %o1, 0x4, %o1
 1:     cmp             %o2, 0
        be,pt           %XCC, 85f
@@ -504,9 +617,9 @@ FUNC_NAME:          /* %o0=dst, %o1=src, %o2=len */
         sub            %g0, %g1, %g1
        sub             %o2, %g1, %o2
 
-1:     EX_LD(LOAD(ldub, %o1, %o5))
+1:     EX_LD(LOAD(ldub, %o1, %o5), U1_g1_0)
        subcc           %g1, 1, %g1
-       EX_ST(STORE(stb, %o5, %o1 + %o3))
+       EX_ST(STORE(stb, %o5, %o1 + %o3), U1_g1_1)
        bgu,pt          %icc, 1b
         add            %o1, 1, %o1
 
@@ -522,16 +635,16 @@ FUNC_NAME:                /* %o0=dst, %o1=src, %o2=len */
 
 8:     mov             64, %o3
        andn            %o1, 0x7, %o1
-       EX_LD(LOAD(ldx, %o1, %g2))
+       EX_LD(LOAD(ldx, %o1, %g2), U1_o2_0)
        sub             %o3, %g1, %o3
        andn            %o2, 0x7, %GLOBAL_SPARE
        sllx            %g2, %g1, %g2
-1:     EX_LD(LOAD(ldx, %o1 + 0x8, %g3))
+1:     EX_LD(LOAD(ldx, %o1 + 0x8, %g3), U1_gs_0_o2_adj)
        subcc           %GLOBAL_SPARE, 0x8, %GLOBAL_SPARE
        add             %o1, 0x8, %o1
        srlx            %g3, %o3, %o5
        or              %o5, %g2, %o5
-       EX_ST(STORE(stx, %o5, %o0))
+       EX_ST(STORE(stx, %o5, %o0), U1_gs_8_o2_adj)
        add             %o0, 0x8, %o0
        bgu,pt          %icc, 1b
         sllx           %g3, %g1, %g2
@@ -549,9 +662,9 @@ FUNC_NAME:          /* %o0=dst, %o1=src, %o2=len */
        bne,pn          %XCC, 90f
         sub            %o0, %o1, %o3
 
-1:     EX_LD(LOAD(lduw, %o1, %g1))
+1:     EX_LD(LOAD(lduw, %o1, %g1), U1_o2_0)
        subcc           %o2, 4, %o2
-       EX_ST(STORE(stw, %g1, %o1 + %o3))
+       EX_ST(STORE(stw, %g1, %o1 + %o3), U1_o2_4)
        bgu,pt          %XCC, 1b
         add            %o1, 4, %o1
 
@@ -559,9 +672,9 @@ FUNC_NAME:          /* %o0=dst, %o1=src, %o2=len */
         mov            EX_RETVAL(%o4), %o0
 
        .align          32
-90:    EX_LD(LOAD(ldub, %o1, %g1))
+90:    EX_LD(LOAD(ldub, %o1, %g1), U1_o2_0)
        subcc           %o2, 1, %o2
-       EX_ST(STORE(stb, %g1, %o1 + %o3))
+       EX_ST(STORE(stb, %g1, %o1 + %o3), U1_o2_1)
        bgu,pt          %XCC, 90b
         add            %o1, 1, %o1
        retl
index 88ad73d86fe44b64c2313483e7490cc8ae0ee438..db73010a1af8f18d5baa7515203001045995ce31 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_LD(x)               \
+#define EX_LD(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one;  \
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_LD_FP(x)            \
+#define EX_LD_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_fp;\
+       .word 98b, y##_fp;      \
        .text;                  \
        .align 4;
 
index 845139d7553720ce5fe98d6e30bcb11215f71e2f..c4ee858e352a2be0e028ac757dd399938e89db04 100644 (file)
@@ -3,19 +3,19 @@
  * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#define EX_ST(x)               \
+#define EX_ST(x,y)             \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one;  \
+       .word 98b, y;           \
        .text;                  \
        .align 4;
 
-#define EX_ST_FP(x)            \
+#define EX_ST_FP(x,y)          \
 98:    x;                      \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one_fp;\
+       .word 98b, y##_fp;      \
        .text;                  \
        .align 4;
 
index 491ee69e49951fc2040640e77b896552872c8a0a..54f98706b03b2f53025adb99e086002a0629e9f0 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #ifdef __KERNEL__
+#include <linux/linkage.h>
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #define GLOBAL_SPARE   %g7
 #endif
 
 #ifndef EX_LD
-#define EX_LD(x)       x
+#define EX_LD(x,y)     x
 #endif
 #ifndef EX_LD_FP
-#define EX_LD_FP(x)    x
+#define EX_LD_FP(x,y)  x
 #endif
 
 #ifndef EX_ST
-#define EX_ST(x)       x
+#define EX_ST(x,y)     x
 #endif
 #ifndef EX_ST_FP
-#define EX_ST_FP(x)    x
-#endif
-
-#ifndef EX_RETVAL
-#define EX_RETVAL(x)   x
+#define EX_ST_FP(x,y)  x
 #endif
 
 #ifndef LOAD
         */
 
        .text
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)   x
+__restore_fp:
+       VISExitHalf
+       retl
+        nop
+ENTRY(U3_retl_o2_plus_g2_plus_g1_plus_1_fp)
+       add     %g1, 1, %g1
+       add     %g2, %g1, %g2
+       ba,pt   %xcc, __restore_fp
+        add    %o2, %g2, %o0
+ENDPROC(U3_retl_o2_plus_g2_plus_g1_plus_1_fp)
+ENTRY(U3_retl_o2_plus_g2_fp)
+       ba,pt   %xcc, __restore_fp
+        add    %o2, %g2, %o0
+ENDPROC(U3_retl_o2_plus_g2_fp)
+ENTRY(U3_retl_o2_plus_g2_plus_8_fp)
+       add     %g2, 8, %g2
+       ba,pt   %xcc, __restore_fp
+        add    %o2, %g2, %o0
+ENDPROC(U3_retl_o2_plus_g2_plus_8_fp)
+ENTRY(U3_retl_o2)
+       retl
+        mov    %o2, %o0
+ENDPROC(U3_retl_o2)
+ENTRY(U3_retl_o2_plus_1)
+       retl
+        add    %o2, 1, %o0
+ENDPROC(U3_retl_o2_plus_1)
+ENTRY(U3_retl_o2_plus_4)
+       retl
+        add    %o2, 4, %o0
+ENDPROC(U3_retl_o2_plus_4)
+ENTRY(U3_retl_o2_plus_8)
+       retl
+        add    %o2, 8, %o0
+ENDPROC(U3_retl_o2_plus_8)
+ENTRY(U3_retl_o2_plus_g1_plus_1)
+       add     %g1, 1, %g1
+       retl
+        add    %o2, %g1, %o0
+ENDPROC(U3_retl_o2_plus_g1_plus_1)
+ENTRY(U3_retl_o2_fp)
+       ba,pt   %xcc, __restore_fp
+        mov    %o2, %o0
+ENDPROC(U3_retl_o2_fp)
+ENTRY(U3_retl_o2_plus_o3_sll_6_plus_0x80_fp)
+       sll     %o3, 6, %o3
+       add     %o3, 0x80, %o3
+       ba,pt   %xcc, __restore_fp
+        add    %o2, %o3, %o0
+ENDPROC(U3_retl_o2_plus_o3_sll_6_plus_0x80_fp)
+ENTRY(U3_retl_o2_plus_o3_sll_6_plus_0x40_fp)
+       sll     %o3, 6, %o3
+       add     %o3, 0x40, %o3
+       ba,pt   %xcc, __restore_fp
+        add    %o2, %o3, %o0
+ENDPROC(U3_retl_o2_plus_o3_sll_6_plus_0x40_fp)
+ENTRY(U3_retl_o2_plus_GS_plus_0x10)
+       add     GLOBAL_SPARE, 0x10, GLOBAL_SPARE
+       retl
+        add    %o2, GLOBAL_SPARE, %o0
+ENDPROC(U3_retl_o2_plus_GS_plus_0x10)
+ENTRY(U3_retl_o2_plus_GS_plus_0x08)
+       add     GLOBAL_SPARE, 0x08, GLOBAL_SPARE
+       retl
+        add    %o2, GLOBAL_SPARE, %o0
+ENDPROC(U3_retl_o2_plus_GS_plus_0x08)
+ENTRY(U3_retl_o2_and_7_plus_GS)
+       and     %o2, 7, %o2
+       retl
+        add    %o2, GLOBAL_SPARE, %o2
+ENDPROC(U3_retl_o2_and_7_plus_GS)
+ENTRY(U3_retl_o2_and_7_plus_GS_plus_8)
+       add     GLOBAL_SPARE, 8, GLOBAL_SPARE
+       and     %o2, 7, %o2
+       retl
+        add    %o2, GLOBAL_SPARE, %o2
+ENDPROC(U3_retl_o2_and_7_plus_GS_plus_8)
+#endif
+
        .align          64
 
        /* The cheetah's flexible spine, oversized liver, enlarged heart,
@@ -126,8 +204,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
         and            %g2, 0x38, %g2
 
 1:     subcc           %g1, 0x1, %g1
-       EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
-       EX_ST_FP(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
+       EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3), U3_retl_o2_plus_g2_plus_g1_plus_1)
+       EX_ST_FP(STORE(stb, %o3, %o1 + GLOBAL_SPARE), U3_retl_o2_plus_g2_plus_g1_plus_1)
        bgu,pt          %XCC, 1b
         add            %o1, 0x1, %o1
 
@@ -138,20 +216,20 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        be,pt           %icc, 3f
         alignaddr      %o1, %g0, %o1
 
-       EX_LD_FP(LOAD(ldd, %o1, %f4))
-1:     EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
+       EX_LD_FP(LOAD(ldd, %o1, %f4), U3_retl_o2_plus_g2)
+1:     EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6), U3_retl_o2_plus_g2)
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f4, %f6, %f0
-       EX_ST_FP(STORE(std, %f0, %o0))
+       EX_ST_FP(STORE(std, %f0, %o0), U3_retl_o2_plus_g2_plus_8)
        be,pn           %icc, 3f
         add            %o0, 0x8, %o0
 
-       EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4), U3_retl_o2_plus_g2)
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f6, %f4, %f2
-       EX_ST_FP(STORE(std, %f2, %o0))
+       EX_ST_FP(STORE(std, %f2, %o0), U3_retl_o2_plus_g2_plus_8)
        bne,pt          %icc, 1b
         add            %o0, 0x8, %o0
 
@@ -161,25 +239,25 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        LOAD(prefetch, %o1 + 0x080, #one_read)
        LOAD(prefetch, %o1 + 0x0c0, #one_read)
        LOAD(prefetch, %o1 + 0x100, #one_read)
-       EX_LD_FP(LOAD(ldd, %o1 + 0x000, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x000, %f0), U3_retl_o2)
        LOAD(prefetch, %o1 + 0x140, #one_read)
-       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2), U3_retl_o2)
        LOAD(prefetch, %o1 + 0x180, #one_read)
-       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4), U3_retl_o2)
        LOAD(prefetch, %o1 + 0x1c0, #one_read)
        faligndata      %f0, %f2, %f16
-       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6), U3_retl_o2)
        faligndata      %f2, %f4, %f18
-       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8), U3_retl_o2)
        faligndata      %f4, %f6, %f20
-       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10), U3_retl_o2)
        faligndata      %f6, %f8, %f22
 
-       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12), U3_retl_o2)
        faligndata      %f8, %f10, %f24
-       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14), U3_retl_o2)
        faligndata      %f10, %f12, %f26
-       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0), U3_retl_o2)
 
        subcc           GLOBAL_SPARE, 0x80, GLOBAL_SPARE
        add             %o1, 0x40, %o1
@@ -190,26 +268,26 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
        .align          64
 1:
-       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2), U3_retl_o2_plus_o3_sll_6_plus_0x80)
        faligndata      %f12, %f14, %f28
-       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4), U3_retl_o2_plus_o3_sll_6_plus_0x80)
        faligndata      %f14, %f0, %f30
-       EX_ST_FP(STORE_BLK(%f16, %o0))
-       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
+       EX_ST_FP(STORE_BLK(%f16, %o0), U3_retl_o2_plus_o3_sll_6_plus_0x80)
+       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f0, %f2, %f16
        add             %o0, 0x40, %o0
 
-       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f2, %f4, %f18
-       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f4, %f6, %f20
-       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        subcc           %o3, 0x01, %o3
        faligndata      %f6, %f8, %f22
-       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14), U3_retl_o2_plus_o3_sll_6_plus_0x80)
 
        faligndata      %f8, %f10, %f24
-       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0), U3_retl_o2_plus_o3_sll_6_plus_0x80)
        LOAD(prefetch, %o1 + 0x1c0, #one_read)
        faligndata      %f10, %f12, %f26
        bg,pt           %XCC, 1b
@@ -217,29 +295,29 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
        /* Finally we copy the last full 64-byte block. */
 2:
-       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2), U3_retl_o2_plus_o3_sll_6_plus_0x80)
        faligndata      %f12, %f14, %f28
-       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4), U3_retl_o2_plus_o3_sll_6_plus_0x80)
        faligndata      %f14, %f0, %f30
-       EX_ST_FP(STORE_BLK(%f16, %o0))
-       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
+       EX_ST_FP(STORE_BLK(%f16, %o0), U3_retl_o2_plus_o3_sll_6_plus_0x80)
+       EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f0, %f2, %f16
-       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f2, %f4, %f18
-       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f4, %f6, %f20
-       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f6, %f8, %f22
-       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        faligndata      %f8, %f10, %f24
        cmp             %g1, 0
        be,pt           %XCC, 1f
         add            %o0, 0x40, %o0
-       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0), U3_retl_o2_plus_o3_sll_6_plus_0x40)
 1:     faligndata      %f10, %f12, %f26
        faligndata      %f12, %f14, %f28
        faligndata      %f14, %f0, %f30
-       EX_ST_FP(STORE_BLK(%f16, %o0))
+       EX_ST_FP(STORE_BLK(%f16, %o0), U3_retl_o2_plus_o3_sll_6_plus_0x40)
        add             %o0, 0x40, %o0
        add             %o1, 0x40, %o1
        membar          #Sync
@@ -259,20 +337,20 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
        sub             %o2, %g2, %o2
        be,a,pt         %XCC, 1f
-        EX_LD_FP(LOAD(ldd, %o1 + 0x00, %f0))
+        EX_LD_FP(LOAD(ldd, %o1 + 0x00, %f0), U3_retl_o2_plus_g2)
 
-1:     EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f2))
+1:     EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f2), U3_retl_o2_plus_g2)
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f0, %f2, %f8
-       EX_ST_FP(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0), U3_retl_o2_plus_g2_plus_8)
        be,pn           %XCC, 2f
         add            %o0, 0x8, %o0
-       EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f0))
+       EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f0), U3_retl_o2_plus_g2)
        add             %o1, 0x8, %o1
        subcc           %g2, 0x8, %g2
        faligndata      %f2, %f0, %f8
-       EX_ST_FP(STORE(std, %f8, %o0))
+       EX_ST_FP(STORE(std, %f8, %o0), U3_retl_o2_plus_g2_plus_8)
        bne,pn          %XCC, 1b
         add            %o0, 0x8, %o0
 
@@ -292,30 +370,33 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
         andcc          %o2, 0x8, %g0
        be,pt           %icc, 1f
         nop
-       EX_LD(LOAD(ldx, %o1, %o5))
-       EX_ST(STORE(stx, %o5, %o1 + %o3))
+       EX_LD(LOAD(ldx, %o1, %o5), U3_retl_o2)
+       EX_ST(STORE(stx, %o5, %o1 + %o3), U3_retl_o2)
        add             %o1, 0x8, %o1
+       sub             %o2, 8, %o2
 
 1:     andcc           %o2, 0x4, %g0
        be,pt           %icc, 1f
         nop
-       EX_LD(LOAD(lduw, %o1, %o5))
-       EX_ST(STORE(stw, %o5, %o1 + %o3))
+       EX_LD(LOAD(lduw, %o1, %o5), U3_retl_o2)
+       EX_ST(STORE(stw, %o5, %o1 + %o3), U3_retl_o2)
        add             %o1, 0x4, %o1
+       sub             %o2, 4, %o2
 
 1:     andcc           %o2, 0x2, %g0
        be,pt           %icc, 1f
         nop
-       EX_LD(LOAD(lduh, %o1, %o5))
-       EX_ST(STORE(sth, %o5, %o1 + %o3))
+       EX_LD(LOAD(lduh, %o1, %o5), U3_retl_o2)
+       EX_ST(STORE(sth, %o5, %o1 + %o3), U3_retl_o2)
        add             %o1, 0x2, %o1
+       sub             %o2, 2, %o2
 
 1:     andcc           %o2, 0x1, %g0
        be,pt           %icc, 85f
         nop
-       EX_LD(LOAD(ldub, %o1, %o5))
+       EX_LD(LOAD(ldub, %o1, %o5), U3_retl_o2)
        ba,pt           %xcc, 85f
-        EX_ST(STORE(stb, %o5, %o1 + %o3))
+        EX_ST(STORE(stb, %o5, %o1 + %o3), U3_retl_o2)
 
        .align          64
 70: /* 16 < len <= 64 */
@@ -326,26 +407,26 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
        andn            %o2, 0xf, GLOBAL_SPARE
        and             %o2, 0xf, %o2
 1:     subcc           GLOBAL_SPARE, 0x10, GLOBAL_SPARE
-       EX_LD(LOAD(ldx, %o1 + 0x00, %o5))
-       EX_LD(LOAD(ldx, %o1 + 0x08, %g1))
-       EX_ST(STORE(stx, %o5, %o1 + %o3))
+       EX_LD(LOAD(ldx, %o1 + 0x00, %o5), U3_retl_o2_plus_GS_plus_0x10)
+       EX_LD(LOAD(ldx, %o1 + 0x08, %g1), U3_retl_o2_plus_GS_plus_0x10)
+       EX_ST(STORE(stx, %o5, %o1 + %o3), U3_retl_o2_plus_GS_plus_0x10)
        add             %o1, 0x8, %o1
-       EX_ST(STORE(stx, %g1, %o1 + %o3))
+       EX_ST(STORE(stx, %g1, %o1 + %o3), U3_retl_o2_plus_GS_plus_0x08)
        bgu,pt          %XCC, 1b
         add            %o1, 0x8, %o1
 73:    andcc           %o2, 0x8, %g0
        be,pt           %XCC, 1f
         nop
        sub             %o2, 0x8, %o2
-       EX_LD(LOAD(ldx, %o1, %o5))
-       EX_ST(STORE(stx, %o5, %o1 + %o3))
+       EX_LD(LOAD(ldx, %o1, %o5), U3_retl_o2_plus_8)
+       EX_ST(STORE(stx, %o5, %o1 + %o3), U3_retl_o2_plus_8)
        add             %o1, 0x8, %o1
 1:     andcc           %o2, 0x4, %g0
        be,pt           %XCC, 1f
         nop
        sub             %o2, 0x4, %o2
-       EX_LD(LOAD(lduw, %o1, %o5))
-       EX_ST(STORE(stw, %o5, %o1 + %o3))
+       EX_LD(LOAD(lduw, %o1, %o5), U3_retl_o2_plus_4)
+       EX_ST(STORE(stw, %o5, %o1 + %o3), U3_retl_o2_plus_4)
        add             %o1, 0x4, %o1
 1:     cmp             %o2, 0
        be,pt           %XCC, 85f
@@ -361,8 +442,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
        sub             %o2, %g1, %o2
 
 1:     subcc           %g1, 1, %g1
-       EX_LD(LOAD(ldub, %o1, %o5))
-       EX_ST(STORE(stb, %o5, %o1 + %o3))
+       EX_LD(LOAD(ldub, %o1, %o5), U3_retl_o2_plus_g1_plus_1)
+       EX_ST(STORE(stb, %o5, %o1 + %o3), U3_retl_o2_plus_g1_plus_1)
        bgu,pt          %icc, 1b
         add            %o1, 1, %o1
 
@@ -378,16 +459,16 @@ FUNC_NAME:        /* %o0=dst, %o1=src, %o2=len */
 
 8:     mov             64, %o3
        andn            %o1, 0x7, %o1
-       EX_LD(LOAD(ldx, %o1, %g2))
+       EX_LD(LOAD(ldx, %o1, %g2), U3_retl_o2)
        sub             %o3, %g1, %o3
        andn            %o2, 0x7, GLOBAL_SPARE
        sllx            %g2, %g1, %g2
-1:     EX_LD(LOAD(ldx, %o1 + 0x8, %g3))
+1:     EX_LD(LOAD(ldx, %o1 + 0x8, %g3), U3_retl_o2_and_7_plus_GS)
        subcc           GLOBAL_SPARE, 0x8, GLOBAL_SPARE
        add             %o1, 0x8, %o1
        srlx            %g3, %o3, %o5
        or              %o5, %g2, %o5
-       EX_ST(STORE(stx, %o5, %o0))
+       EX_ST(STORE(stx, %o5, %o0), U3_retl_o2_and_7_plus_GS_plus_8)
        add             %o0, 0x8, %o0
        bgu,pt          %icc, 1b
         sllx           %g3, %g1, %g2
@@ -407,8 +488,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
 
 1:
        subcc           %o2, 4, %o2
-       EX_LD(LOAD(lduw, %o1, %g1))
-       EX_ST(STORE(stw, %g1, %o1 + %o3))
+       EX_LD(LOAD(lduw, %o1, %g1), U3_retl_o2_plus_4)
+       EX_ST(STORE(stw, %g1, %o1 + %o3), U3_retl_o2_plus_4)
        bgu,pt          %XCC, 1b
         add            %o1, 4, %o1
 
@@ -418,8 +499,8 @@ FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
        .align          32
 90:
        subcc           %o2, 1, %o2
-       EX_LD(LOAD(ldub, %o1, %g1))
-       EX_ST(STORE(stb, %g1, %o1 + %o3))
+       EX_LD(LOAD(ldub, %o1, %g1), U3_retl_o2_plus_1)
+       EX_ST(STORE(stb, %g1, %o1 + %o3), U3_retl_o2_plus_1)
        bgu,pt          %XCC, 90b
         add            %o1, 1, %o1
        retl
index 482de093bdaeb3f33c1b9b2ed51396df2a10c1fe..0252b218de45ac0685c440de07d0d2d0891834e9 100644 (file)
@@ -9,18 +9,33 @@
 
 #define XCC xcc
 
-#define EX(x,y)                        \
+#define EX(x,y,z)              \
 98:    x,y;                    \
        .section __ex_table,"a";\
        .align 4;               \
-       .word 98b, __retl_one;  \
+       .word 98b, z;           \
        .text;                  \
        .align 4;
 
+#define EX_O4(x,y) EX(x,y,__retl_o4_plus_8)
+#define EX_O2_4(x,y) EX(x,y,__retl_o2_plus_4)
+#define EX_O2_1(x,y) EX(x,y,__retl_o2_plus_1)
+
        .register       %g2,#scratch
        .register       %g3,#scratch
 
        .text
+__retl_o4_plus_8:
+       add     %o4, %o2, %o4
+       retl
+        add    %o4, 8, %o0
+__retl_o2_plus_4:
+       retl
+        add    %o2, 4, %o0
+__retl_o2_plus_1:
+       retl
+        add    %o2, 1, %o0
+
        .align  32
 
        /* Don't try to get too fancy here, just nice and
@@ -45,8 +60,8 @@ ENTRY(___copy_in_user)        /* %o0=dst, %o1=src, %o2=len */
        andn            %o2, 0x7, %o4
        and             %o2, 0x7, %o2
 1:     subcc           %o4, 0x8, %o4
-       EX(ldxa [%o1] %asi, %o5)
-       EX(stxa %o5, [%o0] %asi)
+       EX_O4(ldxa [%o1] %asi, %o5)
+       EX_O4(stxa %o5, [%o0] %asi)
        add             %o1, 0x8, %o1
        bgu,pt          %XCC, 1b
         add            %o0, 0x8, %o0
@@ -54,8 +69,8 @@ ENTRY(___copy_in_user)        /* %o0=dst, %o1=src, %o2=len */
        be,pt           %XCC, 1f
         nop
        sub             %o2, 0x4, %o2
-       EX(lduwa [%o1] %asi, %o5)
-       EX(stwa %o5, [%o0] %asi)
+       EX_O2_4(lduwa [%o1] %asi, %o5)
+       EX_O2_4(stwa %o5, [%o0] %asi)
        add             %o1, 0x4, %o1
        add             %o0, 0x4, %o0
 1:     cmp             %o2, 0
@@ -71,8 +86,8 @@ ENTRY(___copy_in_user)        /* %o0=dst, %o1=src, %o2=len */
 
 82:
        subcc           %o2, 4, %o2
-       EX(lduwa [%o1] %asi, %g1)
-       EX(stwa %g1, [%o0] %asi)
+       EX_O2_4(lduwa [%o1] %asi, %g1)
+       EX_O2_4(stwa %g1, [%o0] %asi)
        add             %o1, 4, %o1
        bgu,pt          %XCC, 82b
         add            %o0, 4, %o0
@@ -83,8 +98,8 @@ ENTRY(___copy_in_user)        /* %o0=dst, %o1=src, %o2=len */
        .align  32
 90:
        subcc           %o2, 1, %o2
-       EX(lduba [%o1] %asi, %g1)
-       EX(stba %g1, [%o0] %asi)
+       EX_O2_1(lduba [%o1] %asi, %g1)
+       EX_O2_1(stba %g1, [%o0] %asi)
        add             %o1, 1, %o1
        bgu,pt          %XCC, 90b
         add            %o0, 1, %o0
diff --git a/arch/sparc/lib/user_fixup.c b/arch/sparc/lib/user_fixup.c
deleted file mode 100644 (file)
index ac96ae2..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* user_fixup.c: Fix up user copy faults.
- *
- * Copyright (C) 2004 David S. Miller <davem@redhat.com>
- */
-
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-
-#include <asm/uaccess.h>
-
-/* Calculating the exact fault address when using
- * block loads and stores can be very complicated.
- *
- * Instead of trying to be clever and handling all
- * of the cases, just fix things up simply here.
- */
-
-static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset)
-{
-       unsigned long fault_addr = current_thread_info()->fault_address;
-       unsigned long end = start + size;
-
-       if (fault_addr < start || fault_addr >= end) {
-               *offset = 0;
-       } else {
-               *offset = fault_addr - start;
-               size = end - fault_addr;
-       }
-       return size;
-}
-
-unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size)
-{
-       unsigned long offset;
-
-       size = compute_size((unsigned long) from, size, &offset);
-       if (likely(size))
-               memset(to + offset, 0, size);
-
-       return size;
-}
-EXPORT_SYMBOL(copy_from_user_fixup);
-
-unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size)
-{
-       unsigned long offset;
-
-       return compute_size((unsigned long) to, size, &offset);
-}
-EXPORT_SYMBOL(copy_to_user_fixup);
-
-unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size)
-{
-       unsigned long fault_addr = current_thread_info()->fault_address;
-       unsigned long start = (unsigned long) to;
-       unsigned long end = start + size;
-
-       if (fault_addr >= start && fault_addr < end)
-               return end - fault_addr;
-
-       start = (unsigned long) from;
-       end = start + size;
-       if (fault_addr >= start && fault_addr < end)
-               return end - fault_addr;
-
-       return size;
-}
-EXPORT_SYMBOL(copy_in_user_fixup);
index 4e06750a5d295649660ff4ca0998eb03b00da9e9..cd0e32bbcb1de0f6b16bce4ccd3f8b89acaa18b9 100644 (file)
@@ -238,7 +238,8 @@ slow:
                pages += nr;
 
                ret = get_user_pages_unlocked(start,
-                       (end - start) >> PAGE_SHIFT, write, 0, pages);
+                       (end - start) >> PAGE_SHIFT, pages,
+                       write ? FOLL_WRITE : 0);
 
                /* Have to be a bit careful with return values */
                if (nr > 0) {
index 439784b7b7ac6e5951a6c1c6ab126dddc5fae915..37aa537b3ad841522d9a13c2b4695edb7b092a28 100644 (file)
@@ -802,8 +802,10 @@ struct mdesc_mblock {
 };
 static struct mdesc_mblock *mblocks;
 static int num_mblocks;
+static int find_numa_node_for_addr(unsigned long pa,
+                                  struct node_mem_mask *pnode_mask);
 
-static unsigned long ra_to_pa(unsigned long addr)
+static unsigned long __init ra_to_pa(unsigned long addr)
 {
        int i;
 
@@ -819,8 +821,11 @@ static unsigned long ra_to_pa(unsigned long addr)
        return addr;
 }
 
-static int find_node(unsigned long addr)
+static int __init find_node(unsigned long addr)
 {
+       static bool search_mdesc = true;
+       static struct node_mem_mask last_mem_mask = { ~0UL, ~0UL };
+       static int last_index;
        int i;
 
        addr = ra_to_pa(addr);
@@ -830,13 +835,30 @@ static int find_node(unsigned long addr)
                if ((addr & p->mask) == p->val)
                        return i;
        }
-       /* The following condition has been observed on LDOM guests.*/
-       WARN_ONCE(1, "find_node: A physical address doesn't match a NUMA node"
-               " rule. Some physical memory will be owned by node 0.");
-       return 0;
+       /* The following condition has been observed on LDOM guests because
+        * node_masks only contains the best latency mask and value.
+        * LDOM guest's mdesc can contain a single latency group to
+        * cover multiple address range. Print warning message only if the
+        * address cannot be found in node_masks nor mdesc.
+        */
+       if ((search_mdesc) &&
+           ((addr & last_mem_mask.mask) != last_mem_mask.val)) {
+               /* find the available node in the mdesc */
+               last_index = find_numa_node_for_addr(addr, &last_mem_mask);
+               numadbg("find_node: latency group for address 0x%lx is %d\n",
+                       addr, last_index);
+               if ((last_index < 0) || (last_index >= num_node_masks)) {
+                       /* WARN_ONCE() and use default group 0 */
+                       WARN_ONCE(1, "find_node: A physical address doesn't match a NUMA node rule. Some physical memory will be owned by node 0.");
+                       search_mdesc = false;
+                       last_index = 0;
+               }
+       }
+
+       return last_index;
 }
 
-static u64 memblock_nid_range(u64 start, u64 end, int *nid)
+static u64 __init memblock_nid_range(u64 start, u64 end, int *nid)
 {
        *nid = find_node(start);
        start += PAGE_SIZE;
@@ -1160,6 +1182,41 @@ int __node_distance(int from, int to)
        return numa_latency[from][to];
 }
 
+static int find_numa_node_for_addr(unsigned long pa,
+                                  struct node_mem_mask *pnode_mask)
+{
+       struct mdesc_handle *md = mdesc_grab();
+       u64 node, arc;
+       int i = 0;
+
+       node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups");
+       if (node == MDESC_NODE_NULL)
+               goto out;
+
+       mdesc_for_each_node_by_name(md, node, "group") {
+               mdesc_for_each_arc(arc, md, node, MDESC_ARC_TYPE_FWD) {
+                       u64 target = mdesc_arc_target(md, arc);
+                       struct mdesc_mlgroup *m = find_mlgroup(target);
+
+                       if (!m)
+                               continue;
+                       if ((pa & m->mask) == m->match) {
+                               if (pnode_mask) {
+                                       pnode_mask->mask = m->mask;
+                                       pnode_mask->val = m->match;
+                               }
+                               mdesc_release(md);
+                               return i;
+                       }
+               }
+               i++;
+       }
+
+out:
+       mdesc_release(md);
+       return -1;
+}
+
 static int __init find_best_numa_node_for_mlgroup(struct mdesc_mlgroup *grp)
 {
        int i;
index f2b77112e9d8bb50f4f05346e955fb4c5f6746a9..e20fbbafb0b04af0fa85b21188cd6c851c132e6e 100644 (file)
@@ -27,6 +27,20 @@ static inline int tag_compare(unsigned long tag, unsigned long vaddr)
        return (tag == (vaddr >> 22));
 }
 
+static void flush_tsb_kernel_range_scan(unsigned long start, unsigned long end)
+{
+       unsigned long idx;
+
+       for (idx = 0; idx < KERNEL_TSB_NENTRIES; idx++) {
+               struct tsb *ent = &swapper_tsb[idx];
+               unsigned long match = idx << 13;
+
+               match |= (ent->tag << 22);
+               if (match >= start && match < end)
+                       ent->tag = (1UL << TSB_TAG_INVALID_BIT);
+       }
+}
+
 /* TSB flushes need only occur on the processor initiating the address
  * space modification, not on each cpu the address space has run on.
  * Only the TLB flush needs that treatment.
@@ -36,6 +50,9 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
 {
        unsigned long v;
 
+       if ((end - start) >> PAGE_SHIFT >= 2 * KERNEL_TSB_NENTRIES)
+               return flush_tsb_kernel_range_scan(start, end);
+
        for (v = start; v < end; v += PAGE_SIZE) {
                unsigned long hash = tsb_hash(v, PAGE_SHIFT,
                                              KERNEL_TSB_NENTRIES);
index b4f4733abc6ea8f9e6ef6abafbc75f0b16b08003..5d2fd6cd31896b87a3373a59cbfc3130808c6908 100644 (file)
@@ -30,7 +30,7 @@
        .text
        .align          32
        .globl          __flush_tlb_mm
-__flush_tlb_mm:                /* 18 insns */
+__flush_tlb_mm:                /* 19 insns */
        /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
        ldxa            [%o1] ASI_DMMU, %g2
        cmp             %g2, %o0
@@ -81,7 +81,7 @@ __flush_tlb_page:     /* 22 insns */
 
        .align          32
        .globl          __flush_tlb_pending
-__flush_tlb_pending:   /* 26 insns */
+__flush_tlb_pending:   /* 27 insns */
        /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
        rdpr            %pstate, %g7
        sllx            %o1, 3, %o1
@@ -113,12 +113,14 @@ __flush_tlb_pending:      /* 26 insns */
 
        .align          32
        .globl          __flush_tlb_kernel_range
-__flush_tlb_kernel_range:      /* 16 insns */
+__flush_tlb_kernel_range:      /* 31 insns */
        /* %o0=start, %o1=end */
        cmp             %o0, %o1
        be,pn           %xcc, 2f
+        sub            %o1, %o0, %o3
+       srlx            %o3, 18, %o4
+       brnz,pn         %o4, __spitfire_flush_tlb_kernel_range_slow
         sethi          %hi(PAGE_SIZE), %o4
-       sub             %o1, %o0, %o3
        sub             %o3, %o4, %o3
        or              %o0, 0x20, %o0          ! Nucleus
 1:     stxa            %g0, [%o0 + %o3] ASI_DMMU_DEMAP
@@ -131,6 +133,41 @@ __flush_tlb_kernel_range:  /* 16 insns */
        retl
         nop
        nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
+__spitfire_flush_tlb_kernel_range_slow:
+       mov             63 * 8, %o4
+1:     ldxa            [%o4] ASI_ITLB_DATA_ACCESS, %o3
+       andcc           %o3, 0x40, %g0                  /* _PAGE_L_4U */
+       bne,pn          %xcc, 2f
+        mov            TLB_TAG_ACCESS, %o3
+       stxa            %g0, [%o3] ASI_IMMU
+       stxa            %g0, [%o4] ASI_ITLB_DATA_ACCESS
+       membar          #Sync
+2:     ldxa            [%o4] ASI_DTLB_DATA_ACCESS, %o3
+       andcc           %o3, 0x40, %g0
+       bne,pn          %xcc, 2f
+        mov            TLB_TAG_ACCESS, %o3
+       stxa            %g0, [%o3] ASI_DMMU
+       stxa            %g0, [%o4] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
+2:     sub             %o4, 8, %o4
+       brgez,pt        %o4, 1b
+        nop
+       retl
+        nop
 
 __spitfire_flush_tlb_mm_slow:
        rdpr            %pstate, %g1
@@ -285,6 +322,40 @@ __cheetah_flush_tlb_pending:       /* 27 insns */
        retl
         wrpr           %g7, 0x0, %pstate
 
+__cheetah_flush_tlb_kernel_range:      /* 31 insns */
+       /* %o0=start, %o1=end */
+       cmp             %o0, %o1
+       be,pn           %xcc, 2f
+        sub            %o1, %o0, %o3
+       srlx            %o3, 18, %o4
+       brnz,pn         %o4, 3f
+        sethi          %hi(PAGE_SIZE), %o4
+       sub             %o3, %o4, %o3
+       or              %o0, 0x20, %o0          ! Nucleus
+1:     stxa            %g0, [%o0 + %o3] ASI_DMMU_DEMAP
+       stxa            %g0, [%o0 + %o3] ASI_IMMU_DEMAP
+       membar          #Sync
+       brnz,pt         %o3, 1b
+        sub            %o3, %o4, %o3
+2:     sethi           %hi(KERNBASE), %o3
+       flush           %o3
+       retl
+        nop
+3:     mov             0x80, %o4
+       stxa            %g0, [%o4] ASI_DMMU_DEMAP
+       membar          #Sync
+       stxa            %g0, [%o4] ASI_IMMU_DEMAP
+       membar          #Sync
+       retl
+        nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
 #ifdef DCACHE_ALIASING_POSSIBLE
 __cheetah_flush_dcache_page: /* 11 insns */
        sethi           %hi(PAGE_OFFSET), %g1
@@ -309,19 +380,28 @@ __hypervisor_tlb_tl0_error:
        ret
         restore
 
-__hypervisor_flush_tlb_mm: /* 10 insns */
+__hypervisor_flush_tlb_mm: /* 19 insns */
        mov             %o0, %o2        /* ARG2: mmu context */
        mov             0, %o0          /* ARG0: CPU lists unimplemented */
        mov             0, %o1          /* ARG1: CPU lists unimplemented */
        mov             HV_MMU_ALL, %o3 /* ARG3: flags */
        mov             HV_FAST_MMU_DEMAP_CTX, %o5
        ta              HV_FAST_TRAP
-       brnz,pn         %o0, __hypervisor_tlb_tl0_error
+       brnz,pn         %o0, 1f
         mov            HV_FAST_MMU_DEMAP_CTX, %o1
        retl
         nop
+1:     sethi           %hi(__hypervisor_tlb_tl0_error), %o5
+       jmpl            %o5 + %lo(__hypervisor_tlb_tl0_error), %g0
+        nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
 
-__hypervisor_flush_tlb_page: /* 11 insns */
+__hypervisor_flush_tlb_page: /* 22 insns */
        /* %o0 = context, %o1 = vaddr */
        mov             %o0, %g2
        mov             %o1, %o0              /* ARG0: vaddr + IMMU-bit */
@@ -330,12 +410,23 @@ __hypervisor_flush_tlb_page: /* 11 insns */
        srlx            %o0, PAGE_SHIFT, %o0
        sllx            %o0, PAGE_SHIFT, %o0
        ta              HV_MMU_UNMAP_ADDR_TRAP
-       brnz,pn         %o0, __hypervisor_tlb_tl0_error
+       brnz,pn         %o0, 1f
         mov            HV_MMU_UNMAP_ADDR_TRAP, %o1
        retl
         nop
+1:     sethi           %hi(__hypervisor_tlb_tl0_error), %o2
+       jmpl            %o2 + %lo(__hypervisor_tlb_tl0_error), %g0
+        nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
 
-__hypervisor_flush_tlb_pending: /* 16 insns */
+__hypervisor_flush_tlb_pending: /* 27 insns */
        /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
        sllx            %o1, 3, %g1
        mov             %o2, %g2
@@ -347,31 +438,57 @@ __hypervisor_flush_tlb_pending: /* 16 insns */
        srlx            %o0, PAGE_SHIFT, %o0
        sllx            %o0, PAGE_SHIFT, %o0
        ta              HV_MMU_UNMAP_ADDR_TRAP
-       brnz,pn         %o0, __hypervisor_tlb_tl0_error
+       brnz,pn         %o0, 1f
         mov            HV_MMU_UNMAP_ADDR_TRAP, %o1
        brnz,pt         %g1, 1b
         nop
        retl
         nop
+1:     sethi           %hi(__hypervisor_tlb_tl0_error), %o2
+       jmpl            %o2 + %lo(__hypervisor_tlb_tl0_error), %g0
+        nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
 
-__hypervisor_flush_tlb_kernel_range: /* 16 insns */
+__hypervisor_flush_tlb_kernel_range: /* 31 insns */
        /* %o0=start, %o1=end */
        cmp             %o0, %o1
        be,pn           %xcc, 2f
-        sethi          %hi(PAGE_SIZE), %g3
-       mov             %o0, %g1
-       sub             %o1, %g1, %g2
+        sub            %o1, %o0, %g2
+       srlx            %g2, 18, %g3
+       brnz,pn         %g3, 4f
+        mov            %o0, %g1
+       sethi           %hi(PAGE_SIZE), %g3
        sub             %g2, %g3, %g2
 1:     add             %g1, %g2, %o0   /* ARG0: virtual address */
        mov             0, %o1          /* ARG1: mmu context */
        mov             HV_MMU_ALL, %o2 /* ARG2: flags */
        ta              HV_MMU_UNMAP_ADDR_TRAP
-       brnz,pn         %o0, __hypervisor_tlb_tl0_error
+       brnz,pn         %o0, 3f
         mov            HV_MMU_UNMAP_ADDR_TRAP, %o1
        brnz,pt         %g2, 1b
         sub            %g2, %g3, %g2
 2:     retl
         nop
+3:     sethi           %hi(__hypervisor_tlb_tl0_error), %o2
+       jmpl            %o2 + %lo(__hypervisor_tlb_tl0_error), %g0
+        nop
+4:     mov             0, %o0          /* ARG0: CPU lists unimplemented */
+       mov             0, %o1          /* ARG1: CPU lists unimplemented */
+       mov             0, %o2          /* ARG2: mmu context == nucleus */
+       mov             HV_MMU_ALL, %o3 /* ARG3: flags */
+       mov             HV_FAST_MMU_DEMAP_CTX, %o5
+       ta              HV_FAST_TRAP
+       brnz,pn         %o0, 3b
+        mov            HV_FAST_MMU_DEMAP_CTX, %o1
+       retl
+        nop
 
 #ifdef DCACHE_ALIASING_POSSIBLE
        /* XXX Niagara and friends have an 8K cache, so no aliasing is
@@ -394,43 +511,6 @@ tlb_patch_one:
        retl
         nop
 
-       .globl          cheetah_patch_cachetlbops
-cheetah_patch_cachetlbops:
-       save            %sp, -128, %sp
-
-       sethi           %hi(__flush_tlb_mm), %o0
-       or              %o0, %lo(__flush_tlb_mm), %o0
-       sethi           %hi(__cheetah_flush_tlb_mm), %o1
-       or              %o1, %lo(__cheetah_flush_tlb_mm), %o1
-       call            tlb_patch_one
-        mov            19, %o2
-
-       sethi           %hi(__flush_tlb_page), %o0
-       or              %o0, %lo(__flush_tlb_page), %o0
-       sethi           %hi(__cheetah_flush_tlb_page), %o1
-       or              %o1, %lo(__cheetah_flush_tlb_page), %o1
-       call            tlb_patch_one
-        mov            22, %o2
-
-       sethi           %hi(__flush_tlb_pending), %o0
-       or              %o0, %lo(__flush_tlb_pending), %o0
-       sethi           %hi(__cheetah_flush_tlb_pending), %o1
-       or              %o1, %lo(__cheetah_flush_tlb_pending), %o1
-       call            tlb_patch_one
-        mov            27, %o2
-
-#ifdef DCACHE_ALIASING_POSSIBLE
-       sethi           %hi(__flush_dcache_page), %o0
-       or              %o0, %lo(__flush_dcache_page), %o0
-       sethi           %hi(__cheetah_flush_dcache_page), %o1
-       or              %o1, %lo(__cheetah_flush_dcache_page), %o1
-       call            tlb_patch_one
-        mov            11, %o2
-#endif /* DCACHE_ALIASING_POSSIBLE */
-
-       ret
-        restore
-
 #ifdef CONFIG_SMP
        /* These are all called by the slaves of a cross call, at
         * trap level 1, with interrupts fully disabled.
@@ -447,7 +527,7 @@ cheetah_patch_cachetlbops:
         */
        .align          32
        .globl          xcall_flush_tlb_mm
-xcall_flush_tlb_mm:    /* 21 insns */
+xcall_flush_tlb_mm:    /* 24 insns */
        mov             PRIMARY_CONTEXT, %g2
        ldxa            [%g2] ASI_DMMU, %g3
        srlx            %g3, CTX_PGSZ1_NUC_SHIFT, %g4
@@ -469,9 +549,12 @@ xcall_flush_tlb_mm:        /* 21 insns */
        nop
        nop
        nop
+       nop
+       nop
+       nop
 
        .globl          xcall_flush_tlb_page
-xcall_flush_tlb_page:  /* 17 insns */
+xcall_flush_tlb_page:  /* 20 insns */
        /* %g5=context, %g1=vaddr */
        mov             PRIMARY_CONTEXT, %g4
        ldxa            [%g4] ASI_DMMU, %g2
@@ -490,15 +573,20 @@ xcall_flush_tlb_page:     /* 17 insns */
        retry
        nop
        nop
+       nop
+       nop
+       nop
 
        .globl          xcall_flush_tlb_kernel_range
-xcall_flush_tlb_kernel_range:  /* 25 insns */
+xcall_flush_tlb_kernel_range:  /* 44 insns */
        sethi           %hi(PAGE_SIZE - 1), %g2
        or              %g2, %lo(PAGE_SIZE - 1), %g2
        andn            %g1, %g2, %g1
        andn            %g7, %g2, %g7
        sub             %g7, %g1, %g3
-       add             %g2, 1, %g2
+       srlx            %g3, 18, %g2
+       brnz,pn         %g2, 2f
+        add            %g2, 1, %g2
        sub             %g3, %g2, %g3
        or              %g1, 0x20, %g1          ! Nucleus
 1:     stxa            %g0, [%g1 + %g3] ASI_DMMU_DEMAP
@@ -507,8 +595,25 @@ xcall_flush_tlb_kernel_range:      /* 25 insns */
        brnz,pt         %g3, 1b
         sub            %g3, %g2, %g3
        retry
-       nop
-       nop
+2:     mov             63 * 8, %g1
+1:     ldxa            [%g1] ASI_ITLB_DATA_ACCESS, %g2
+       andcc           %g2, 0x40, %g0                  /* _PAGE_L_4U */
+       bne,pn          %xcc, 2f
+        mov            TLB_TAG_ACCESS, %g2
+       stxa            %g0, [%g2] ASI_IMMU
+       stxa            %g0, [%g1] ASI_ITLB_DATA_ACCESS
+       membar          #Sync
+2:     ldxa            [%g1] ASI_DTLB_DATA_ACCESS, %g2
+       andcc           %g2, 0x40, %g0
+       bne,pn          %xcc, 2f
+        mov            TLB_TAG_ACCESS, %g2
+       stxa            %g0, [%g2] ASI_DMMU
+       stxa            %g0, [%g1] ASI_DTLB_DATA_ACCESS
+       membar          #Sync
+2:     sub             %g1, 8, %g1
+       brgez,pt        %g1, 1b
+        nop
+       retry
        nop
        nop
        nop
@@ -637,6 +742,52 @@ xcall_fetch_glob_pmu_n4:
 
        retry
 
+__cheetah_xcall_flush_tlb_kernel_range:        /* 44 insns */
+       sethi           %hi(PAGE_SIZE - 1), %g2
+       or              %g2, %lo(PAGE_SIZE - 1), %g2
+       andn            %g1, %g2, %g1
+       andn            %g7, %g2, %g7
+       sub             %g7, %g1, %g3
+       srlx            %g3, 18, %g2
+       brnz,pn         %g2, 2f
+        add            %g2, 1, %g2
+       sub             %g3, %g2, %g3
+       or              %g1, 0x20, %g1          ! Nucleus
+1:     stxa            %g0, [%g1 + %g3] ASI_DMMU_DEMAP
+       stxa            %g0, [%g1 + %g3] ASI_IMMU_DEMAP
+       membar          #Sync
+       brnz,pt         %g3, 1b
+        sub            %g3, %g2, %g3
+       retry
+2:     mov             0x80, %g2
+       stxa            %g0, [%g2] ASI_DMMU_DEMAP
+       membar          #Sync
+       stxa            %g0, [%g2] ASI_IMMU_DEMAP
+       membar          #Sync
+       retry
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
 #ifdef DCACHE_ALIASING_POSSIBLE
        .align          32
        .globl          xcall_flush_dcache_page_cheetah
@@ -700,7 +851,7 @@ __hypervisor_tlb_xcall_error:
        ba,a,pt %xcc, rtrap
 
        .globl          __hypervisor_xcall_flush_tlb_mm
-__hypervisor_xcall_flush_tlb_mm: /* 21 insns */
+__hypervisor_xcall_flush_tlb_mm: /* 24 insns */
        /* %g5=ctx, g1,g2,g3,g4,g7=scratch, %g6=unusable */
        mov             %o0, %g2
        mov             %o1, %g3
@@ -714,7 +865,7 @@ __hypervisor_xcall_flush_tlb_mm: /* 21 insns */
        mov             HV_FAST_MMU_DEMAP_CTX, %o5
        ta              HV_FAST_TRAP
        mov             HV_FAST_MMU_DEMAP_CTX, %g6
-       brnz,pn         %o0, __hypervisor_tlb_xcall_error
+       brnz,pn         %o0, 1f
         mov            %o0, %g5
        mov             %g2, %o0
        mov             %g3, %o1
@@ -723,9 +874,12 @@ __hypervisor_xcall_flush_tlb_mm: /* 21 insns */
        mov             %g7, %o5
        membar          #Sync
        retry
+1:     sethi           %hi(__hypervisor_tlb_xcall_error), %g4
+       jmpl            %g4 + %lo(__hypervisor_tlb_xcall_error), %g0
+        nop
 
        .globl          __hypervisor_xcall_flush_tlb_page
-__hypervisor_xcall_flush_tlb_page: /* 17 insns */
+__hypervisor_xcall_flush_tlb_page: /* 20 insns */
        /* %g5=ctx, %g1=vaddr */
        mov             %o0, %g2
        mov             %o1, %g3
@@ -737,42 +891,64 @@ __hypervisor_xcall_flush_tlb_page: /* 17 insns */
        sllx            %o0, PAGE_SHIFT, %o0
        ta              HV_MMU_UNMAP_ADDR_TRAP
        mov             HV_MMU_UNMAP_ADDR_TRAP, %g6
-       brnz,a,pn       %o0, __hypervisor_tlb_xcall_error
+       brnz,a,pn       %o0, 1f
         mov            %o0, %g5
        mov             %g2, %o0
        mov             %g3, %o1
        mov             %g4, %o2
        membar          #Sync
        retry
+1:     sethi           %hi(__hypervisor_tlb_xcall_error), %g4
+       jmpl            %g4 + %lo(__hypervisor_tlb_xcall_error), %g0
+        nop
 
        .globl          __hypervisor_xcall_flush_tlb_kernel_range
-__hypervisor_xcall_flush_tlb_kernel_range: /* 25 insns */
+__hypervisor_xcall_flush_tlb_kernel_range: /* 44 insns */
        /* %g1=start, %g7=end, g2,g3,g4,g5,g6=scratch */
        sethi           %hi(PAGE_SIZE - 1), %g2
        or              %g2, %lo(PAGE_SIZE - 1), %g2
        andn            %g1, %g2, %g1
        andn            %g7, %g2, %g7
        sub             %g7, %g1, %g3
+       srlx            %g3, 18, %g7
        add             %g2, 1, %g2
        sub             %g3, %g2, %g3
        mov             %o0, %g2
        mov             %o1, %g4
-       mov             %o2, %g7
+       brnz,pn         %g7, 2f
+        mov            %o2, %g7
 1:     add             %g1, %g3, %o0   /* ARG0: virtual address */
        mov             0, %o1          /* ARG1: mmu context */
        mov             HV_MMU_ALL, %o2 /* ARG2: flags */
        ta              HV_MMU_UNMAP_ADDR_TRAP
        mov             HV_MMU_UNMAP_ADDR_TRAP, %g6
-       brnz,pn         %o0, __hypervisor_tlb_xcall_error
+       brnz,pn         %o0, 1f
         mov            %o0, %g5
        sethi           %hi(PAGE_SIZE), %o2
        brnz,pt         %g3, 1b
         sub            %g3, %o2, %g3
-       mov             %g2, %o0
+5:     mov             %g2, %o0
        mov             %g4, %o1
        mov             %g7, %o2
        membar          #Sync
        retry
+1:     sethi           %hi(__hypervisor_tlb_xcall_error), %g4
+       jmpl            %g4 + %lo(__hypervisor_tlb_xcall_error), %g0
+        nop
+2:     mov             %o3, %g1
+       mov             %o5, %g3
+       mov             0, %o0          /* ARG0: CPU lists unimplemented */
+       mov             0, %o1          /* ARG1: CPU lists unimplemented */
+       mov             0, %o2          /* ARG2: mmu context == nucleus */
+       mov             HV_MMU_ALL, %o3 /* ARG3: flags */
+       mov             HV_FAST_MMU_DEMAP_CTX, %o5
+       ta              HV_FAST_TRAP
+       mov             %g1, %o3
+       brz,pt          %o0, 5b
+        mov            %g3, %o5
+       mov             HV_FAST_MMU_DEMAP_CTX, %g6
+       ba,pt           %xcc, 1b
+        clr            %g5
 
        /* These just get rescheduled to PIL vectors. */
        .globl          xcall_call_function
@@ -809,6 +985,58 @@ xcall_kgdb_capture:
 
 #endif /* CONFIG_SMP */
 
+       .globl          cheetah_patch_cachetlbops
+cheetah_patch_cachetlbops:
+       save            %sp, -128, %sp
+
+       sethi           %hi(__flush_tlb_mm), %o0
+       or              %o0, %lo(__flush_tlb_mm), %o0
+       sethi           %hi(__cheetah_flush_tlb_mm), %o1
+       or              %o1, %lo(__cheetah_flush_tlb_mm), %o1
+       call            tlb_patch_one
+        mov            19, %o2
+
+       sethi           %hi(__flush_tlb_page), %o0
+       or              %o0, %lo(__flush_tlb_page), %o0
+       sethi           %hi(__cheetah_flush_tlb_page), %o1
+       or              %o1, %lo(__cheetah_flush_tlb_page), %o1
+       call            tlb_patch_one
+        mov            22, %o2
+
+       sethi           %hi(__flush_tlb_pending), %o0
+       or              %o0, %lo(__flush_tlb_pending), %o0
+       sethi           %hi(__cheetah_flush_tlb_pending), %o1
+       or              %o1, %lo(__cheetah_flush_tlb_pending), %o1
+       call            tlb_patch_one
+        mov            27, %o2
+
+       sethi           %hi(__flush_tlb_kernel_range), %o0
+       or              %o0, %lo(__flush_tlb_kernel_range), %o0
+       sethi           %hi(__cheetah_flush_tlb_kernel_range), %o1
+       or              %o1, %lo(__cheetah_flush_tlb_kernel_range), %o1
+       call            tlb_patch_one
+        mov            31, %o2
+
+#ifdef DCACHE_ALIASING_POSSIBLE
+       sethi           %hi(__flush_dcache_page), %o0
+       or              %o0, %lo(__flush_dcache_page), %o0
+       sethi           %hi(__cheetah_flush_dcache_page), %o1
+       or              %o1, %lo(__cheetah_flush_dcache_page), %o1
+       call            tlb_patch_one
+        mov            11, %o2
+#endif /* DCACHE_ALIASING_POSSIBLE */
+
+#ifdef CONFIG_SMP
+       sethi           %hi(xcall_flush_tlb_kernel_range), %o0
+       or              %o0, %lo(xcall_flush_tlb_kernel_range), %o0
+       sethi           %hi(__cheetah_xcall_flush_tlb_kernel_range), %o1
+       or              %o1, %lo(__cheetah_xcall_flush_tlb_kernel_range), %o1
+       call            tlb_patch_one
+        mov            44, %o2
+#endif /* CONFIG_SMP */
+
+       ret
+        restore
 
        .globl          hypervisor_patch_cachetlbops
 hypervisor_patch_cachetlbops:
@@ -819,28 +1047,28 @@ hypervisor_patch_cachetlbops:
        sethi           %hi(__hypervisor_flush_tlb_mm), %o1
        or              %o1, %lo(__hypervisor_flush_tlb_mm), %o1
        call            tlb_patch_one
-        mov            10, %o2
+        mov            19, %o2
 
        sethi           %hi(__flush_tlb_page), %o0
        or              %o0, %lo(__flush_tlb_page), %o0
        sethi           %hi(__hypervisor_flush_tlb_page), %o1
        or              %o1, %lo(__hypervisor_flush_tlb_page), %o1
        call            tlb_patch_one
-        mov            11, %o2
+        mov            22, %o2
 
        sethi           %hi(__flush_tlb_pending), %o0
        or              %o0, %lo(__flush_tlb_pending), %o0
        sethi           %hi(__hypervisor_flush_tlb_pending), %o1
        or              %o1, %lo(__hypervisor_flush_tlb_pending), %o1
        call            tlb_patch_one
-        mov            16, %o2
+        mov            27, %o2
 
        sethi           %hi(__flush_tlb_kernel_range), %o0
        or              %o0, %lo(__flush_tlb_kernel_range), %o0
        sethi           %hi(__hypervisor_flush_tlb_kernel_range), %o1
        or              %o1, %lo(__hypervisor_flush_tlb_kernel_range), %o1
        call            tlb_patch_one
-        mov            16, %o2
+        mov            31, %o2
 
 #ifdef DCACHE_ALIASING_POSSIBLE
        sethi           %hi(__flush_dcache_page), %o0
@@ -857,21 +1085,21 @@ hypervisor_patch_cachetlbops:
        sethi           %hi(__hypervisor_xcall_flush_tlb_mm), %o1
        or              %o1, %lo(__hypervisor_xcall_flush_tlb_mm), %o1
        call            tlb_patch_one
-        mov            21, %o2
+        mov            24, %o2
 
        sethi           %hi(xcall_flush_tlb_page), %o0
        or              %o0, %lo(xcall_flush_tlb_page), %o0
        sethi           %hi(__hypervisor_xcall_flush_tlb_page), %o1
        or              %o1, %lo(__hypervisor_xcall_flush_tlb_page), %o1
        call            tlb_patch_one
-        mov            17, %o2
+        mov            20, %o2
 
        sethi           %hi(xcall_flush_tlb_kernel_range), %o0
        or              %o0, %lo(xcall_flush_tlb_kernel_range), %o0
        sethi           %hi(__hypervisor_xcall_flush_tlb_kernel_range), %o1
        or              %o1, %lo(__hypervisor_xcall_flush_tlb_kernel_range), %o1
        call            tlb_patch_one
-        mov            25, %o2
+        mov            44, %o2
 #endif /* CONFIG_SMP */
 
        ret
index 6160761d5f611319ecd9f838d3f407c934e61ae6..4810e48dbbbf57cc8d77ff4ce7bcb8356b142341 100644 (file)
@@ -61,4 +61,7 @@
  */
 #define __write_once __read_mostly
 
+/* __ro_after_init is the generic name for the tile arch __write_once. */
+#define __ro_after_init __read_mostly
+
 #endif /* _ASM_TILE_CACHE_H */
index 178989e6d3e3ae1403ae9dc1f108126fedb6e2c8..ea960d6609177faa86780e6164f26e4d3ef51ac2 100644 (file)
@@ -218,8 +218,8 @@ void do_timer_interrupt(struct pt_regs *regs, int fault_num)
  */
 unsigned long long sched_clock(void)
 {
-       return clocksource_cyc2ns(get_cycles(),
-                                 sched_clock_mult, SCHED_CLOCK_SHIFT);
+       return mult_frac(get_cycles(),
+                        sched_clock_mult, 1ULL << SCHED_CLOCK_SHIFT);
 }
 
 int setup_profiling_timer(unsigned int multiplier)
index 536ccfcc01c673c4e3196a4fe57276cf7d7d53a8..34d9e15857c3ba69681038b3ee032c0efa8126f8 100644 (file)
@@ -40,8 +40,8 @@ GCOV_PROFILE := n
 UBSAN_SANITIZE :=n
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
-ifeq ($(CONFIG_RELOCATABLE),y)
-# If kernel is relocatable, build compressed kernel as PIE.
+# Compressed kernel should be built as PIE since it may be loaded at any
+# address by the bootloader.
 ifeq ($(CONFIG_X86_32),y)
 LDFLAGS += $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
 else
@@ -51,7 +51,6 @@ else
 LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
        && echo "-z noreloc-overflow -pie --no-dynamic-linker")
 endif
-endif
 LDFLAGS_vmlinux := -T
 
 hostprogs-y    := mkpiggy
index 26240dde081e82e696b9a828a191b01c7bdaf0a9..4224ede43b4edc3df93b5e669cc091d73b9186b5 100644 (file)
@@ -87,6 +87,12 @@ int validate_cpu(void)
                return -1;
        }
 
+       if (CONFIG_X86_MINIMUM_CPU_FAMILY <= 4 && !IS_ENABLED(CONFIG_M486) &&
+           !has_eflag(X86_EFLAGS_ID)) {
+               printf("This kernel requires a CPU with the CPUID instruction.  Build with CONFIG_M486=y to run on this CPU.\n");
+               return -1;
+       }
+
        if (err_flags) {
                puts("This kernel requires the following features "
                     "not present on the CPU:\n");
index 0ab5ee1c26af057d9965470d42d5a9edd65c9ae7..aa8b0672f87a451865283f5f3e9f3d2c03992870 100644 (file)
@@ -888,7 +888,7 @@ static int helper_rfc4106_encrypt(struct aead_request *req)
        unsigned long auth_tag_len = crypto_aead_authsize(tfm);
        u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
        struct scatter_walk src_sg_walk;
-       struct scatter_walk dst_sg_walk;
+       struct scatter_walk dst_sg_walk = {};
        unsigned int i;
 
        /* Assuming we are supporting rfc4106 64-bit extended */
@@ -968,7 +968,7 @@ static int helper_rfc4106_decrypt(struct aead_request *req)
        u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
        u8 authTag[16];
        struct scatter_walk src_sg_walk;
-       struct scatter_walk dst_sg_walk;
+       struct scatter_walk dst_sg_walk = {};
        unsigned int i;
 
        if (unlikely(req->assoclen != 16 && req->assoclen != 20))
index 77f28ce9c6464e71a942f767082391502c8fa80d..9976fcecd17edfca5d5dbfe94c2dad0a635edf2d 100644 (file)
@@ -5,8 +5,8 @@
 OBJECT_FILES_NON_STANDARD_entry_$(BITS).o   := y
 OBJECT_FILES_NON_STANDARD_entry_64_compat.o := y
 
-CFLAGS_syscall_64.o            += -Wno-override-init
-CFLAGS_syscall_32.o            += -Wno-override-init
+CFLAGS_syscall_64.o            += $(call cc-option,-Wno-override-init,)
+CFLAGS_syscall_32.o            += $(call cc-option,-Wno-override-init,)
 obj-y                          := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
 obj-y                          += common.o
 
index ff6ef7b3082237e5d223de9a9986202761566d17..2b361854254414662c17b531e2cacb8d5bb696b9 100644 (file)
 380    i386    pkey_mprotect           sys_pkey_mprotect
 381    i386    pkey_alloc              sys_pkey_alloc
 382    i386    pkey_free               sys_pkey_free
-#383   i386    pkey_get                sys_pkey_get
-#384   i386    pkey_set                sys_pkey_set
index 2f024d02511da47e12cacfbeea9826c440de8f9e..e93ef0b38db8e16a38f83e2e3f08dfb8d5fff4a0 100644 (file)
 329    common  pkey_mprotect           sys_pkey_mprotect
 330    common  pkey_alloc              sys_pkey_alloc
 331    common  pkey_free               sys_pkey_free
-#332   common  pkey_get                sys_pkey_get
-#333   common  pkey_set                sys_pkey_set
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index f5f4b3fbbbc2924cbac3fe24d45d949e0997dc8e..afb222b63caeb0217ef34d9b2b193b6b59bd190d 100644 (file)
@@ -662,7 +662,13 @@ static int __init amd_core_pmu_init(void)
                pr_cont("Fam15h ");
                x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
                break;
-
+       case 0x17:
+               pr_cont("Fam17h ");
+               /*
+                * In family 17h, there are no event constraints in the PMC hardware.
+                * We fallback to using default amd_get_event_constraints.
+                */
+               break;
        default:
                pr_err("core perfctr but no constraints; unknown hardware!\n");
                return -ENODEV;
index d31735f37ed7d0435b8aca5d2f476e04a249b6e8..6e395c9969002839fc0fd1e94f95fe0ba77abe0b 100644 (file)
@@ -69,7 +69,7 @@ u64 x86_perf_event_update(struct perf_event *event)
        int shift = 64 - x86_pmu.cntval_bits;
        u64 prev_raw_count, new_raw_count;
        int idx = hwc->idx;
-       s64 delta;
+       u64 delta;
 
        if (idx == INTEL_PMC_IDX_FIXED_BTS)
                return 0;
@@ -2352,7 +2352,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
                frame.next_frame     = 0;
                frame.return_address = 0;
 
-               if (!access_ok(VERIFY_READ, fp, 8))
+               if (!valid_user_frame(fp, sizeof(frame)))
                        break;
 
                bytes = __copy_from_user_nmi(&frame.next_frame, fp, 4);
@@ -2362,9 +2362,6 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
                if (bytes != 0)
                        break;
 
-               if (!valid_user_frame(fp, sizeof(frame)))
-                       break;
-
                perf_callchain_store(entry, cs_base + frame.return_address);
                fp = compat_ptr(ss_base + frame.next_frame);
        }
@@ -2413,7 +2410,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
                frame.next_frame             = NULL;
                frame.return_address = 0;
 
-               if (!access_ok(VERIFY_READ, fp, sizeof(*fp) * 2))
+               if (!valid_user_frame(fp, sizeof(frame)))
                        break;
 
                bytes = __copy_from_user_nmi(&frame.next_frame, fp, sizeof(*fp));
@@ -2423,9 +2420,6 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs
                if (bytes != 0)
                        break;
 
-               if (!valid_user_frame(fp, sizeof(frame)))
-                       break;
-
                perf_callchain_store(entry, frame.return_address);
                fp = (void __user *)frame.next_frame;
        }
index a3a9eb84b5cf16ffebd5bf46c69037db4d1e3794..cb8522290e6a3f6dc3b5baacfc618d0ee8db65e3 100644 (file)
@@ -3607,10 +3607,14 @@ __init int intel_pmu_init(void)
 
        /*
         * Quirk: v2 perfmon does not report fixed-purpose events, so
-        * assume at least 3 events:
+        * assume at least 3 events, when not running in a hypervisor:
         */
-       if (version > 1)
-               x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3);
+       if (version > 1) {
+               int assume = 3 * !boot_cpu_has(X86_FEATURE_HYPERVISOR);
+
+               x86_pmu.num_counters_fixed =
+                       max((int)edx.split.num_counters_fixed, assume);
+       }
 
        if (boot_cpu_has(X86_FEATURE_PDCM)) {
                u64 capabilities;
@@ -3898,6 +3902,7 @@ __init int intel_pmu_init(void)
                break;
 
        case INTEL_FAM6_XEON_PHI_KNL:
+       case INTEL_FAM6_XEON_PHI_KNM:
                memcpy(hw_cache_event_ids,
                       slm_hw_cache_event_ids, sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs,
@@ -3912,7 +3917,7 @@ __init int intel_pmu_init(void)
                x86_pmu.flags |= PMU_FL_HAS_RSP_1;
                x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
 
-               pr_cont("Knights Landing events, ");
+               pr_cont("Knights Landing/Mill events, ");
                break;
 
        case INTEL_FAM6_SKYLAKE_MOBILE:
@@ -4029,7 +4034,7 @@ __init int intel_pmu_init(void)
 
        /* Support full width counters using alternative MSR range */
        if (x86_pmu.intel_cap.full_width_write) {
-               x86_pmu.max_period = x86_pmu.cntval_mask;
+               x86_pmu.max_period = x86_pmu.cntval_mask >> 1;
                x86_pmu.perfctr = MSR_IA32_PMC0;
                pr_cont("full-width counters, ");
        }
index 3ca87b5a8677608c86ac8d748b59ead0d160f580..da51e5a3e2ff799d54257aa3db5151b4723c8292 100644 (file)
@@ -48,7 +48,8 @@
  *                            Scope: Core
  *     MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter
  *                            perf code: 0x02
- *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW
+ *                                             SKL,KNL
  *                            Scope: Core
  *     MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
  *                            perf code: 0x03
  *                            Scope: Core
  *     MSR_PKG_C2_RESIDENCY:  Package C2 Residency Counter.
  *                            perf code: 0x00
- *                            Available model: SNB,IVB,HSW,BDW,SKL
+ *                            Available model: SNB,IVB,HSW,BDW,SKL,KNL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C3_RESIDENCY:  Package C3 Residency Counter.
  *                            perf code: 0x01
- *                            Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *                            Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C6_RESIDENCY:  Package C6 Residency Counter.
  *                            perf code: 0x02
- *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL
+ *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW
+ *                                             SKL,KNL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C7_RESIDENCY:  Package C7 Residency Counter.
  *                            perf code: 0x03
@@ -118,6 +120,7 @@ struct cstate_model {
 
 /* Quirk flags */
 #define SLM_PKG_C6_USE_C7_MSR  (1UL << 0)
+#define KNL_CORE_C6_MSR                (1UL << 1)
 
 struct perf_cstate_msr {
        u64     msr;
@@ -488,6 +491,18 @@ static const struct cstate_model slm_cstates __initconst = {
        .quirks                 = SLM_PKG_C6_USE_C7_MSR,
 };
 
+
+static const struct cstate_model knl_cstates __initconst = {
+       .core_events            = BIT(PERF_CSTATE_CORE_C6_RES),
+
+       .pkg_events             = BIT(PERF_CSTATE_PKG_C2_RES) |
+                                 BIT(PERF_CSTATE_PKG_C3_RES) |
+                                 BIT(PERF_CSTATE_PKG_C6_RES),
+       .quirks                 = KNL_CORE_C6_MSR,
+};
+
+
+
 #define X86_CSTATES_MODEL(model, states)                               \
        { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long) &(states) }
 
@@ -523,6 +538,9 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
 
        X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_MOBILE,  snb_cstates),
        X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_DESKTOP, snb_cstates),
+
+       X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNL, knl_cstates),
+       X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNM, knl_cstates),
        { },
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
@@ -558,6 +576,11 @@ static int __init cstate_probe(const struct cstate_model *cm)
        if (cm->quirks & SLM_PKG_C6_USE_C7_MSR)
                pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY;
 
+       /* KNL has different MSR for CORE C6 */
+       if (cm->quirks & KNL_CORE_C6_MSR)
+               pkg_msr[PERF_CSTATE_CORE_C6_RES].msr = MSR_KNL_CORE_C6_RESIDENCY;
+
+
        has_cstate_core = cstate_probe_msr(cm->core_events,
                                           PERF_CSTATE_CORE_EVENT_MAX,
                                           core_msr, core_events_attrs);
index 0319311dbdbb548eef4f5b2431c285deea5dd00c..be202390bbd37b00106864123a647786497ce2cd 100644 (file)
@@ -1108,20 +1108,20 @@ static void setup_pebs_sample_data(struct perf_event *event,
        }
 
        /*
-        * We use the interrupt regs as a base because the PEBS record
-        * does not contain a full regs set, specifically it seems to
-        * lack segment descriptors, which get used by things like
-        * user_mode().
+        * We use the interrupt regs as a base because the PEBS record does not
+        * contain a full regs set, specifically it seems to lack segment
+        * descriptors, which get used by things like user_mode().
         *
-        * In the simple case fix up only the IP and BP,SP regs, for
-        * PERF_SAMPLE_IP and PERF_SAMPLE_CALLCHAIN to function properly.
-        * A possible PERF_SAMPLE_REGS will have to transfer all regs.
+        * In the simple case fix up only the IP for PERF_SAMPLE_IP.
+        *
+        * We must however always use BP,SP from iregs for the unwinder to stay
+        * sane; the record BP,SP can point into thin air when the record is
+        * from a previous PMI context or an (I)RET happend between the record
+        * and PMI.
         */
        *regs = *iregs;
        regs->flags = pebs->flags;
        set_linear_ip(regs, pebs->ip);
-       regs->bp = pebs->bp;
-       regs->sp = pebs->sp;
 
        if (sample_type & PERF_SAMPLE_REGS_INTR) {
                regs->ax = pebs->ax;
@@ -1130,10 +1130,21 @@ static void setup_pebs_sample_data(struct perf_event *event,
                regs->dx = pebs->dx;
                regs->si = pebs->si;
                regs->di = pebs->di;
-               regs->bp = pebs->bp;
-               regs->sp = pebs->sp;
 
-               regs->flags = pebs->flags;
+               /*
+                * Per the above; only set BP,SP if we don't need callchains.
+                *
+                * XXX: does this make sense?
+                */
+               if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
+                       regs->bp = pebs->bp;
+                       regs->sp = pebs->sp;
+               }
+
+               /*
+                * Preserve PERF_EFLAGS_VM from set_linear_ip().
+                */
+               regs->flags = pebs->flags | (regs->flags & PERF_EFLAGS_VM);
 #ifndef CONFIG_X86_32
                regs->r8 = pebs->r8;
                regs->r9 = pebs->r9;
index fc6cf21c535e19f4c07deccf4a6444199e5ae39c..81b321ace8e0194d3ce18b29fcb42c20b834a918 100644 (file)
@@ -458,8 +458,8 @@ void intel_pmu_lbr_del(struct perf_event *event)
        if (!x86_pmu.lbr_nr)
                return;
 
-       if (branch_user_callstack(cpuc->br_sel) && event->ctx &&
-                                       event->ctx->task_ctx_data) {
+       if (branch_user_callstack(cpuc->br_sel) &&
+           event->ctx->task_ctx_data) {
                task_ctx = event->ctx->task_ctx_data;
                task_ctx->lbr_callstack_users--;
        }
index b0f0e835a770f7ee959681513bd7e41af39827a0..0a535cea8ff31adf6e06fc32ff763d423a73ab74 100644 (file)
@@ -763,6 +763,7 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = {
        X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, hsw_rapl_init),
 
        X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_rapl_init),
+       X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM, knl_rapl_init),
 
        X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE,  skl_rapl_init),
        X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, skl_rapl_init),
index d9844cc74486e602c7b768e225856323a37025b8..dbaaf7dc8373cb0248a4637abe4a211f266fb2db 100644 (file)
@@ -319,9 +319,9 @@ static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
  */
 static int uncore_pmu_event_init(struct perf_event *event);
 
-static bool is_uncore_event(struct perf_event *event)
+static bool is_box_event(struct intel_uncore_box *box, struct perf_event *event)
 {
-       return event->pmu->event_init == uncore_pmu_event_init;
+       return &box->pmu->pmu == event->pmu;
 }
 
 static int
@@ -340,7 +340,7 @@ uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader,
 
        n = box->n_events;
 
-       if (is_uncore_event(leader)) {
+       if (is_box_event(box, leader)) {
                box->event_list[n] = leader;
                n++;
        }
@@ -349,7 +349,7 @@ uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader,
                return n;
 
        list_for_each_entry(event, &leader->sibling_list, group_entry) {
-               if (!is_uncore_event(event) ||
+               if (!is_box_event(box, event) ||
                    event->state <= PERF_EVENT_STATE_OFF)
                        continue;
 
@@ -1349,6 +1349,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_X,    bdx_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, bdx_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL,   knl_uncore_init),
+       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM,   knl_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP,skl_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X,      skx_uncore_init),
index 5f845eef9a4d682a3598c13946dbdec9fb70adeb..a3dcc12bef4ab3a67aab29c6acf3480920e06952 100644 (file)
@@ -8,8 +8,12 @@
 #define PCI_DEVICE_ID_INTEL_HSW_IMC    0x0c00
 #define PCI_DEVICE_ID_INTEL_HSW_U_IMC  0x0a04
 #define PCI_DEVICE_ID_INTEL_BDW_IMC    0x1604
-#define PCI_DEVICE_ID_INTEL_SKL_IMC    0x191f
-#define PCI_DEVICE_ID_INTEL_SKL_U_IMC  0x190c
+#define PCI_DEVICE_ID_INTEL_SKL_U_IMC  0x1904
+#define PCI_DEVICE_ID_INTEL_SKL_Y_IMC  0x190c
+#define PCI_DEVICE_ID_INTEL_SKL_HD_IMC 0x1900
+#define PCI_DEVICE_ID_INTEL_SKL_HQ_IMC 0x1910
+#define PCI_DEVICE_ID_INTEL_SKL_SD_IMC 0x190f
+#define PCI_DEVICE_ID_INTEL_SKL_SQ_IMC 0x191f
 
 /* SNB event control */
 #define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
@@ -486,24 +490,12 @@ static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
 
        snb_uncore_imc_event_start(event, 0);
 
-       box->n_events++;
-
        return 0;
 }
 
 static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
 {
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       int i;
-
        snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
-
-       for (i = 0; i < box->n_events; i++) {
-               if (event == box->event_list[i]) {
-                       --box->n_events;
-                       break;
-               }
-       }
 }
 
 int snb_pci2phy_map_init(int devid)
@@ -616,13 +608,29 @@ static const struct pci_device_id bdw_uncore_pci_ids[] = {
 
 static const struct pci_device_id skl_uncore_pci_ids[] = {
        { /* IMC */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_IMC),
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_Y_IMC),
                .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
        },
        { /* IMC */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_U_IMC),
                .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
        },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_HD_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_HQ_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_SD_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_SQ_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
 
        { /* end: all zeroes */ },
 };
@@ -666,8 +674,12 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
        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 */
        IMC_DEV(BDW_IMC, &bdw_uncore_pci_driver),    /* 5th Gen Core U */
-       IMC_DEV(SKL_IMC, &skl_uncore_pci_driver),    /* 6th Gen Core */
+       IMC_DEV(SKL_Y_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core Y */
        IMC_DEV(SKL_U_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core U */
+       IMC_DEV(SKL_HD_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core H Dual Core */
+       IMC_DEV(SKL_HQ_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core H Quad Core */
+       IMC_DEV(SKL_SD_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core S Dual Core */
+       IMC_DEV(SKL_SQ_IMC, &skl_uncore_pci_driver),  /* 6th Gen Core S Quad Core */
        {  /* end marker */ }
 };
 
index 5874d8de1f8da111e3e0a682835e42b23af875ff..a77ee026643d23fac4808a1f1c32ca42e4999769 100644 (file)
@@ -113,7 +113,7 @@ struct debug_store {
  * Per register state.
  */
 struct er_account {
-       raw_spinlock_t          lock;   /* per-core: protect structure */
+       raw_spinlock_t      lock;       /* per-core: protect structure */
        u64                 config;     /* extra MSR config */
        u64                 reg;        /* extra MSR number */
        atomic_t            ref;        /* reference count */
index 03d269bed9416925bc35682f1fbd37385ef558b5..24118c0b464090372fbd831a891890ecb8debd9b 100644 (file)
@@ -272,7 +272,6 @@ struct compat_shmid64_ds {
 /*
  * The type of struct elf_prstatus.pr_reg in compatible core dumps.
  */
-#ifdef CONFIG_X86_X32_ABI
 typedef struct user_regs_struct compat_elf_gregset_t;
 
 /* Full regset -- prstatus on x32, otherwise on ia32 */
@@ -281,10 +280,9 @@ typedef struct user_regs_struct compat_elf_gregset_t;
   do { *(int *) (((void *) &((S)->pr_reg)) + R) = (V); } \
   while (0)
 
+#ifdef CONFIG_X86_X32_ABI
 #define COMPAT_USE_64BIT_TIME \
        (!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
-#else
-typedef struct user_regs_struct32 compat_elf_gregset_t;
 #endif
 
 /*
index 1188bc849ee3b3253fd8229fca21bf2d6c87856e..a39629206864e5bb74aaddea15ca1ab762877042 100644 (file)
 #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 
 #define X86_FEATURE_INTEL_PT   ( 7*32+15) /* Intel Processor Trace */
+#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
+#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
index 9ae5ab80a497c35a9fa3048c532bdb9239c395e1..34a46dc076d3610212e6f5c9f0abfb2ab9bc3629 100644 (file)
@@ -64,5 +64,6 @@
 /* Xeon Phi */
 
 #define INTEL_FAM6_XEON_PHI_KNL                0x57 /* Knights Landing */
+#define INTEL_FAM6_XEON_PHI_KNM                0x85 /* Knights Mill */
 
 #endif /* _ASM_X86_INTEL_FAMILY_H */
index 5b6753d1f7f4e35f8066e89555c715badc46ca23..49da9f497b908b676d9ec0c22c8646817bf1f52b 100644 (file)
@@ -17,6 +17,7 @@
 
 extern int intel_mid_pci_init(void);
 extern int intel_mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state);
+extern pci_power_t intel_mid_pci_get_power_state(struct pci_dev *pdev);
 
 extern void intel_mid_pwr_power_off(void);
 
index de25aad0785389c399dd12c843ca2d4d2ff0d112..d34bd370074b46662e5a96014ed4cd5b521f6045 100644 (file)
@@ -351,4 +351,10 @@ extern void arch_phys_wc_del(int handle);
 #define arch_phys_wc_add arch_phys_wc_add
 #endif
 
+#ifdef CONFIG_X86_PAT
+extern int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size);
+extern void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size);
+#define arch_io_reserve_memtype_wc arch_io_reserve_memtype_wc
+#endif
+
 #endif /* _ASM_X86_IO_H */
index 4b20f7304b9c241f58dcaa6b33a486a7308af9c4..bdde80731f490ecc05af1234d99c6ae2820975d4 100644 (file)
@@ -948,7 +948,6 @@ struct kvm_x86_ops {
        int (*get_lpage_level)(void);
        bool (*rdtscp_supported)(void);
        bool (*invpcid_supported)(void);
-       void (*adjust_tsc_offset_guest)(struct kvm_vcpu *vcpu, s64 adjustment);
 
        void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 
@@ -958,8 +957,6 @@ struct kvm_x86_ops {
 
        void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
-       u64 (*read_l1_tsc)(struct kvm_vcpu *vcpu, u64 host_tsc);
-
        void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
 
        int (*check_intercept)(struct kvm_vcpu *vcpu,
index 56f4c6676b29034830d4fdb9c7cdcedd0c14e2a1..78f3760ca1f2985cfcbb278d59fbe71f92f69ea7 100644 (file)
@@ -88,7 +88,6 @@
 
 #define MSR_IA32_RTIT_CTL              0x00000570
 #define MSR_IA32_RTIT_STATUS           0x00000571
-#define MSR_IA32_RTIT_STATUS           0x00000571
 #define MSR_IA32_RTIT_ADDR0_A          0x00000580
 #define MSR_IA32_RTIT_ADDR0_B          0x00000581
 #define MSR_IA32_RTIT_ADDR1_A          0x00000582
index 3d33a719f5c1d8652be749c43ba4b7dc5560c4d5..a34e0d4b957d639afb5978863e57fefb74a173f2 100644 (file)
@@ -103,8 +103,10 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
 ({                                                     \
        long tmp;                                       \
        struct rw_semaphore* ret;                       \
+       register void *__sp asm(_ASM_SP);               \
+                                                       \
        asm volatile("# beginning down_write\n\t"       \
-                    LOCK_PREFIX "  xadd      %1,(%3)\n\t"      \
+                    LOCK_PREFIX "  xadd      %1,(%4)\n\t"      \
                     /* adds 0xffff0001, returns the old value */ \
                     "  test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
                     /* was the active mask 0 before? */\
@@ -112,7 +114,7 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
                     "  call " slow_path "\n"           \
                     "1:\n"                             \
                     "# ending down_write"              \
-                    : "+m" (sem->count), "=d" (tmp), "=a" (ret)        \
+                    : "+m" (sem->count), "=d" (tmp), "=a" (ret), "+r" (__sp) \
                     : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
                     : "memory", "cc");                 \
        ret;                                            \
index 2aaca53c097416bbb305c0014acac1ba6d72dbb0..ad6f5eb07a95bd221fe4e13c8cdb3af0cd27aa37 100644 (file)
@@ -52,6 +52,15 @@ struct task_struct;
 #include <asm/cpufeature.h>
 #include <linux/atomic.h>
 
+struct thread_info {
+       unsigned long           flags;          /* low level flags */
+};
+
+#define INIT_THREAD_INFO(tsk)                  \
+{                                              \
+       .flags          = 0,                    \
+}
+
 #define init_stack             (init_thread_union.stack)
 
 #else /* !__ASSEMBLY__ */
index 8a5abaa7d4533e1592bc6977569c737762089516..931ced8ca345114397536ae1998a438a84889193 100644 (file)
@@ -454,6 +454,7 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger,
                polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
 
        mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
+       acpi_penalize_sci_irq(bus_irq, trigger, polarity);
 
        /*
         * stash over-ride to indicate we've been here
index aeef53ce93e1ca999e77c2f174c6a06f17353362..35690a168cf7491d960b34c978a9125bba78c6a0 100644 (file)
@@ -815,9 +815,9 @@ static __init void map_mmioh_high_uv3(int index, int min_pnode, int max_pnode)
                                l = li;
                        }
                        addr1 = (base << shift) +
-                               f * (unsigned long)(1 << m_io);
+                               f * (1ULL << m_io);
                        addr2 = (base << shift) +
-                               (l + 1) * (unsigned long)(1 << m_io);
+                               (l + 1) * (1ULL << m_io);
                        pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx - 0x%016lx\n",
                                id, fi, li, lnasid, addr1, addr2);
                        if (max_io < l)
index c7364bd633e1d8c1a346c69534ded295bc2ba48d..51287cd90bf65f4ffa6215c4dea0c112aa5f6697 100644 (file)
@@ -1042,8 +1042,11 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
 
        if (apm_info.get_power_status_broken)
                return APM_32_UNSUPPORTED;
-       if (apm_bios_call(&call))
+       if (apm_bios_call(&call)) {
+               if (!call.err)
+                       return APM_NO_ERROR;
                return call.err;
+       }
        *status = call.ebx;
        *bat = call.ecx;
        if (apm_info.get_power_status_swabinminutes) {
index b81fe2d63e15751c2cb7e61fd10dc85cc7f906b0..1e81a37c034e7821580f5165eb4359e209ef7823 100644 (file)
@@ -347,7 +347,6 @@ static void amd_detect_cmp(struct cpuinfo_x86 *c)
 #ifdef CONFIG_SMP
        unsigned bits;
        int cpu = smp_processor_id();
-       unsigned int socket_id, core_complex_id;
 
        bits = c->x86_coreid_bits;
        /* Low order bits define the core id (index of core in socket) */
@@ -365,10 +364,7 @@ static void amd_detect_cmp(struct cpuinfo_x86 *c)
         if (c->x86 != 0x17 || !cpuid_edx(0x80000006))
                return;
 
-       socket_id       = (c->apicid >> bits) - 1;
-       core_complex_id = (c->apicid & ((1 << bits) - 1)) >> 3;
-
-       per_cpu(cpu_llc_id, cpu) = (socket_id << 3) | core_complex_id;
+       per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
 #endif
 }
 
index 9bd910a7dd0abc0d994c6e50250c6d104550dc1e..cc9e980c68ec47b39a8c4ae7ad3497d3d94bd53d 100644 (file)
@@ -978,6 +978,35 @@ static void x86_init_cache_qos(struct cpuinfo_x86 *c)
        }
 }
 
+/*
+ * The physical to logical package id mapping is initialized from the
+ * acpi/mptables information. Make sure that CPUID actually agrees with
+ * that.
+ */
+static void sanitize_package_id(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+       unsigned int pkg, apicid, cpu = smp_processor_id();
+
+       apicid = apic->cpu_present_to_apicid(cpu);
+       pkg = apicid >> boot_cpu_data.x86_coreid_bits;
+
+       if (apicid != c->initial_apicid) {
+               pr_err(FW_BUG "CPU%u: APIC id mismatch. Firmware: %x CPUID: %x\n",
+                      cpu, apicid, c->initial_apicid);
+               c->initial_apicid = apicid;
+       }
+       if (pkg != c->phys_proc_id) {
+               pr_err(FW_BUG "CPU%u: Using firmware package id %u instead of %u\n",
+                      cpu, pkg, c->phys_proc_id);
+               c->phys_proc_id = pkg;
+       }
+       c->logical_proc_id = topology_phys_to_logical_pkg(pkg);
+#else
+       c->logical_proc_id = 0;
+#endif
+}
+
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
@@ -1103,8 +1132,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 #ifdef CONFIG_NUMA
        numa_add_cpu(smp_processor_id());
 #endif
-       /* The boot/hotplug time assigment got cleared, restore it */
-       c->logical_proc_id = topology_phys_to_logical_pkg(c->phys_proc_id);
+       sanitize_package_id(c);
 }
 
 /*
index 620ab06bcf4571c8841b70e35a57657dda2e9985..017bda12caaed9c46f60fccc90f05d861e58e1ba 100644 (file)
@@ -429,7 +429,7 @@ int __init save_microcode_in_initrd_amd(void)
         * We need the physical address of the container for both bitness since
         * boot_params.hdr.ramdisk_image is a physical address.
         */
-       cont    = __pa(container);
+       cont    = __pa_nodebug(container);
        cont_va = container;
 #endif
 
index 8cb57df9398d91a74eec678134844d8ac1052463..1db8dc490b665e751f43f3411cc21079eea75ae2 100644 (file)
@@ -32,6 +32,8 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c)
 
        static const struct cpuid_bit cpuid_bits[] = {
                { X86_FEATURE_INTEL_PT,         CR_EBX,25, 0x00000007, 0 },
+               { X86_FEATURE_AVX512_4VNNIW,    CR_EDX, 2, 0x00000007, 0 },
+               { X86_FEATURE_AVX512_4FMAPS,    CR_EDX, 3, 0x00000007, 0 },
                { X86_FEATURE_APERFMPERF,       CR_ECX, 0, 0x00000006, 0 },
                { X86_FEATURE_EPB,              CR_ECX, 3, 0x00000006, 0 },
                { X86_FEATURE_HW_PSTATE,        CR_EDX, 7, 0x80000007, 0 },
index 81160578b91ac9a053bf5a5f172ea2fb6da1c241..5130985b758b98ea74380ec8991ca1f72d709521 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/div64.h>
 #include <asm/x86_init.h>
 #include <asm/hypervisor.h>
+#include <asm/timer.h>
 #include <asm/apic.h>
 
 #define CPUID_VMWARE_INFO_LEAF 0x40000000
@@ -94,6 +95,10 @@ static void __init vmware_platform_setup(void)
        } else {
                pr_warn("Failed to get TSC freq from the hypervisor\n");
        }
+
+#ifdef CONFIG_X86_IO_APIC
+       no_timer_check = 1;
+#endif
 }
 
 /*
index 9b7cf5c28f5fa8557d23083047995bd93af1a68a..85f854b98a9d24c3e0e6a3d9d83fd6c5b6c57e3f 100644 (file)
@@ -112,7 +112,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
                for (; stack < stack_info.end; stack++) {
                        unsigned long real_addr;
                        int reliable = 0;
-                       unsigned long addr = *stack;
+                       unsigned long addr = READ_ONCE_NOCHECK(*stack);
                        unsigned long *ret_addr_p =
                                unwind_get_return_address_ptr(&state);
 
index b85fe5f91c3fe4901cf766aa1f6996710f844b0d..90e8dde3ec26b1d97d10309d2d796489078b5cdf 100644 (file)
@@ -350,7 +350,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
                 * continue building up new bios map based on this
                 * information
                 */
-               if (current_type != last_type) {
+               if (current_type != last_type || current_type == E820_PRAM) {
                        if (last_type != 0)      {
                                new_bios[new_bios_entry].size =
                                        change_point[chgidx]->addr - last_addr;
index 47004010ad5dd42ec03e5ca075d832ef0c925e38..ebb4e95fbd741b5842b6c4a6320688f99bcf541a 100644 (file)
@@ -521,14 +521,14 @@ void fpu__clear(struct fpu *fpu)
 {
        WARN_ON_FPU(fpu != &current->thread.fpu); /* Almost certainly an anomaly */
 
-       if (!use_eager_fpu() || !static_cpu_has(X86_FEATURE_FPU)) {
-               /* FPU state will be reallocated lazily at the first use. */
-               fpu__drop(fpu);
-       } else {
-               if (!fpu->fpstate_active) {
-                       fpu__activate_curr(fpu);
-                       user_fpu_begin();
-               }
+       fpu__drop(fpu);
+
+       /*
+        * Make sure fpstate is cleared and initialized.
+        */
+       if (static_cpu_has(X86_FEATURE_FPU)) {
+               fpu__activate_curr(fpu);
+               user_fpu_begin();
                copy_init_fpstate_to_fpregs();
        }
 }
index 124aa5c593f8da7aba6643bc609a332744d10ba6..095ef7ddd6ae4d1c6d5476d6e63561963786e793 100644 (file)
@@ -74,6 +74,8 @@ void fpu__xstate_clear_all_cpu_caps(void)
        setup_clear_cpu_cap(X86_FEATURE_MPX);
        setup_clear_cpu_cap(X86_FEATURE_XGETBV1);
        setup_clear_cpu_cap(X86_FEATURE_PKU);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512_4VNNIW);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512_4FMAPS);
 }
 
 /*
index b6b2f0264af36ac272537e5d6689a38361bb60d4..2dabea46f03935f435493117c058a297f5011878 100644 (file)
@@ -665,14 +665,17 @@ __PAGE_ALIGNED_BSS
 initial_pg_pmd:
        .fill 1024*KPMDS,4,0
 #else
-ENTRY(initial_page_table)
+.globl initial_page_table
+initial_page_table:
        .fill 1024,4,0
 #endif
 initial_pg_fixmap:
        .fill 1024,4,0
-ENTRY(empty_zero_page)
+.globl empty_zero_page
+empty_zero_page:
        .fill 4096,1,0
-ENTRY(swapper_pg_dir)
+.globl swapper_pg_dir
+swapper_pg_dir:
        .fill 1024,4,0
 EXPORT_SYMBOL(empty_zero_page)
 
index 28cee019209ce7f7fd9ec160e4409fecf000819f..d9d8d16b69db89df63b5ff33a4e597fcf4e5eba6 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ftrace.h>
 #include <linux/frame.h>
+#include <linux/kasan.h>
 
 #include <asm/text-patching.h>
 #include <asm/cacheflush.h>
@@ -1057,9 +1058,10 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
         * tailcall optimization. So, to be absolutely safe
         * we also save and restore enough stack bytes to cover
         * the argument area.
+        * Use __memcpy() to avoid KASAN stack out-of-bounds reports as we copy
+        * raw stack chunk with redzones:
         */
-       memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
-              MIN_STACK_SIZE(addr));
+       __memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr, MIN_STACK_SIZE(addr));
        regs->flags &= ~X86_EFLAGS_IF;
        trace_hardirqs_off();
        regs->ip = (unsigned long)(jp->entry);
@@ -1080,6 +1082,9 @@ void jprobe_return(void)
 {
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
+       /* Unpoison stack redzones in the frames we are going to jump over. */
+       kasan_unpoison_stack_above_sp_to(kcb->jprobe_saved_sp);
+
        asm volatile (
 #ifdef CONFIG_X86_64
                        "       xchg   %%rbx,%%rsp      \n"
@@ -1118,7 +1123,7 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
                /* It's OK to start function graph tracing again */
                unpause_graph_tracing();
                *regs = kcb->jprobe_saved_regs;
-               memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp));
+               __memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp));
                preempt_enable_no_resched();
                return 1;
        }
index efe73aacf966eb6f54e6c252f4e672a425ba7350..7b0d3da52fb42f288a947f1befe8886319b37ec5 100644 (file)
 
 #ifdef CC_USING_FENTRY
 # define function_hook __fentry__
+EXPORT_SYMBOL(__fentry__)
 #else
 # define function_hook mcount
+EXPORT_SYMBOL(mcount)
 #endif
 
 /* All cases save the original rbp (8 bytes) */
@@ -295,7 +297,6 @@ trace:
        jmp fgraph_trace
 END(function_hook)
 #endif /* CONFIG_DYNAMIC_FTRACE */
-EXPORT_SYMBOL(function_hook)
 #endif /* CONFIG_FUNCTION_TRACER */
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
index 51402a7e4ca6ed040bd727477a0cee9c23426887..0bee04d41bed04406de00732cb1d73e5f6f32c33 100644 (file)
@@ -625,8 +625,6 @@ static void amd_disable_seq_and_redirect_scrub(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3,
                        amd_disable_seq_and_redirect_scrub);
 
-#endif
-
 #if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
 #include <linux/jump_label.h>
 #include <asm/string_64.h>
@@ -657,3 +655,4 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, quirk_intel_brickland_xeon_
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, quirk_intel_brickland_xeon_ras_cap);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2083, quirk_intel_purley_xeon_ras_cap);
 #endif
+#endif
index bbfbca5fea0cda10cf7f56e92d2a19d95a37ecb7..9c337b0e8ba7c4ac5b82a3e4ad979c7d4011b4bf 100644 (file)
@@ -1221,11 +1221,16 @@ void __init setup_arch(char **cmdline_p)
         */
        get_smp_config();
 
+       /*
+        * Systems w/o ACPI and mptables might not have it mapped the local
+        * APIC yet, but prefill_possible_map() might need to access it.
+        */
+       init_apic_mappings();
+
        prefill_possible_map();
 
        init_cpu_to_node();
 
-       init_apic_mappings();
        io_apic_init_mappings();
 
        kvm_guest_init();
index 40df33753bae8d71390b7f4bd81113211a7b67da..ec1f756f9dc9ace1badccd544b6032d64e520360 100644 (file)
@@ -105,9 +105,6 @@ void sigaction_compat_abi(struct k_sigaction *act, struct k_sigaction *oact)
        /* Don't let flags to be set from userspace */
        act->sa.sa_flags &= ~(SA_IA32_ABI | SA_X32_ABI);
 
-       if (user_64bit_mode(current_pt_regs()))
-               return;
-
        if (in_ia32_syscall())
                act->sa.sa_flags |= SA_IA32_ABI;
        if (in_x32_syscall())
index 68f8cc222f255aa1cf5266e2d84d7ceeb2417977..c00cb64bc0a12e5f6f36c37215b05a3afd178db9 100644 (file)
@@ -261,8 +261,10 @@ static inline void __smp_reschedule_interrupt(void)
 
 __visible void smp_reschedule_interrupt(struct pt_regs *regs)
 {
+       irq_enter();
        ack_APIC_irq();
        __smp_reschedule_interrupt();
+       irq_exit();
        /*
         * KVM uses this interrupt to force a cpu out of guest mode
         */
index 951f093a96fe90709827a7f75430ad042c318774..42f5eb7b4f6c85251f4ab65d6de44268b6de06ea 100644 (file)
@@ -1409,15 +1409,17 @@ __init void prefill_possible_map(void)
 
        /* No boot processor was found in mptable or ACPI MADT */
        if (!num_processors) {
-               int apicid = boot_cpu_physical_apicid;
-               int cpu = hard_smp_processor_id();
+               if (boot_cpu_has(X86_FEATURE_APIC)) {
+                       int apicid = boot_cpu_physical_apicid;
+                       int cpu = hard_smp_processor_id();
 
-               pr_warn("Boot CPU (id %d) not listed by BIOS\n", cpu);
+                       pr_warn("Boot CPU (id %d) not listed by BIOS\n", cpu);
 
-               /* Make sure boot cpu is enumerated */
-               if (apic->cpu_present_to_apicid(0) == BAD_APICID &&
-                   apic->apic_id_valid(apicid))
-                       generic_processor_info(apicid, boot_cpu_apic_version);
+                       /* Make sure boot cpu is enumerated */
+                       if (apic->cpu_present_to_apicid(0) == BAD_APICID &&
+                           apic->apic_id_valid(apicid))
+                               generic_processor_info(apicid, boot_cpu_apic_version);
+               }
 
                if (!num_processors)
                        num_processors = 1;
index c9a073866ca7b1f4c6efa5b9db110c591083b3af..a23ce84a3f6ccfefe36a0d3070880aa45d2bc0f5 100644 (file)
@@ -57,7 +57,8 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
        unsigned char opcode[15];
        unsigned long addr = convert_ip_to_linear(child, regs);
 
-       copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
+       copied = access_process_vm(child, addr, opcode, sizeof(opcode),
+                       FOLL_FORCE);
        for (i = 0; i < copied; i++) {
                switch (opcode[i]) {
                /* popf and iret */
index 764a29f84de7feea6346ce1d822af64f14af63ff..85195d447a922785857db0caacc73d6bc9b9490c 100644 (file)
@@ -66,13 +66,36 @@ __init int create_simplefb(const struct screen_info *si,
 {
        struct platform_device *pd;
        struct resource res;
-       unsigned long len;
+       u64 base, size;
+       u32 length;
 
-       /* don't use lfb_size as it may contain the whole VMEM instead of only
-        * the part that is occupied by the framebuffer */
-       len = mode->height * mode->stride;
-       len = PAGE_ALIGN(len);
-       if (len > (u64)si->lfb_size << 16) {
+       /*
+        * If the 64BIT_BASE capability is set, ext_lfb_base will contain the
+        * upper half of the base address. Assemble the address, then make sure
+        * it is valid and we can actually access it.
+        */
+       base = si->lfb_base;
+       if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+               base |= (u64)si->ext_lfb_base << 32;
+       if (!base || (u64)(resource_size_t)base != base) {
+               printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Don't use lfb_size as IORESOURCE size, since it may contain the
+        * entire VMEM, and thus require huge mappings. Use just the part we
+        * need, that is, the part where the framebuffer is located. But verify
+        * that it does not exceed the advertised VMEM.
+        * Note that in case of VBE, the lfb_size is shifted by 16 bits for
+        * historical reasons.
+        */
+       size = si->lfb_size;
+       if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
+               size <<= 16;
+       length = mode->height * mode->stride;
+       length = PAGE_ALIGN(length);
+       if (length > size) {
                printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
                return -EINVAL;
        }
@@ -81,8 +104,8 @@ __init int create_simplefb(const struct screen_info *si,
        memset(&res, 0, sizeof(res));
        res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        res.name = simplefb_resname;
-       res.start = si->lfb_base;
-       res.end = si->lfb_base + len - 1;
+       res.start = base;
+       res.end = res.start + length - 1;
        if (res.end <= res.start)
                return -EINVAL;
 
index 9298993dc8b715adb79e78f2f71be74402e68b7d..22881ddcbb9fc0c0a23ee7faf0578727b09a23f6 100644 (file)
@@ -7,11 +7,15 @@
 
 unsigned long unwind_get_return_address(struct unwind_state *state)
 {
+       unsigned long addr;
+
        if (unwind_done(state))
                return 0;
 
+       addr = READ_ONCE_NOCHECK(*state->sp);
+
        return ftrace_graph_ret_addr(state->task, &state->graph_idx,
-                                    *state->sp, state->sp);
+                                    addr, state->sp);
 }
 EXPORT_SYMBOL_GPL(unwind_get_return_address);
 
@@ -23,9 +27,12 @@ bool unwind_next_frame(struct unwind_state *state)
                return false;
 
        do {
-               for (state->sp++; state->sp < info->end; state->sp++)
-                       if (__kernel_text_address(*state->sp))
+               for (state->sp++; state->sp < info->end; state->sp++) {
+                       unsigned long addr = READ_ONCE_NOCHECK(*state->sp);
+
+                       if (__kernel_text_address(addr))
                                return true;
+               }
 
                state->sp = info->next_sp;
 
@@ -47,7 +54,14 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
        get_stack_info(first_frame, state->task, &state->stack_info,
                       &state->stack_mask);
 
-       if (!__kernel_text_address(*first_frame))
+       /*
+        * The caller can provide the address of the first frame directly
+        * (first_frame) or indirectly (regs->sp) to indicate which stack frame
+        * to start unwinding at.  Skip ahead until we reach it.
+        */
+       if (!unwind_done(state) &&
+           (!on_stack(&state->stack_info, first_frame, sizeof(long)) ||
+           !__kernel_text_address(*first_frame)))
                unwind_next_frame(state);
 }
 EXPORT_SYMBOL_GPL(__unwind_start);
index 4e95d3eb29557bcb99219fddb7b909e23ff3b090..a3ce9d260d68756fa675ce40994b79aedd206413 100644 (file)
@@ -2105,16 +2105,10 @@ static int em_iret(struct x86_emulate_ctxt *ctxt)
 static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
 {
        int rc;
-       unsigned short sel, old_sel;
-       struct desc_struct old_desc, new_desc;
-       const struct x86_emulate_ops *ops = ctxt->ops;
+       unsigned short sel;
+       struct desc_struct new_desc;
        u8 cpl = ctxt->ops->cpl(ctxt);
 
-       /* Assignment of RIP may only fail in 64-bit mode */
-       if (ctxt->mode == X86EMUL_MODE_PROT64)
-               ops->get_segment(ctxt, &old_sel, &old_desc, NULL,
-                                VCPU_SREG_CS);
-
        memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2);
 
        rc = __load_segment_descriptor(ctxt, sel, VCPU_SREG_CS, cpl,
@@ -2124,12 +2118,10 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
                return rc;
 
        rc = assign_eip_far(ctxt, ctxt->src.val, &new_desc);
-       if (rc != X86EMUL_CONTINUE) {
-               WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
-               /* assigning eip failed; restore the old cs */
-               ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS);
-               return rc;
-       }
+       /* Error handling is not implemented. */
+       if (rc != X86EMUL_CONTINUE)
+               return X86EMUL_UNHANDLEABLE;
+
        return rc;
 }
 
@@ -2189,14 +2181,8 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
 {
        int rc;
        unsigned long eip, cs;
-       u16 old_cs;
        int cpl = ctxt->ops->cpl(ctxt);
-       struct desc_struct old_desc, new_desc;
-       const struct x86_emulate_ops *ops = ctxt->ops;
-
-       if (ctxt->mode == X86EMUL_MODE_PROT64)
-               ops->get_segment(ctxt, &old_cs, &old_desc, NULL,
-                                VCPU_SREG_CS);
+       struct desc_struct new_desc;
 
        rc = emulate_pop(ctxt, &eip, ctxt->op_bytes);
        if (rc != X86EMUL_CONTINUE)
@@ -2213,10 +2199,10 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
        if (rc != X86EMUL_CONTINUE)
                return rc;
        rc = assign_eip_far(ctxt, eip, &new_desc);
-       if (rc != X86EMUL_CONTINUE) {
-               WARN_ON(ctxt->mode != X86EMUL_MODE_PROT64);
-               ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
-       }
+       /* Error handling is not implemented. */
+       if (rc != X86EMUL_CONTINUE)
+               return X86EMUL_UNHANDLEABLE;
+
        return rc;
 }
 
@@ -5045,7 +5031,7 @@ done_prefixes:
        /* Decode and fetch the destination operand: register or memory. */
        rc = decode_operand(ctxt, &ctxt->dst, (ctxt->d >> DstShift) & OpMask);
 
-       if (ctxt->rip_relative)
+       if (ctxt->rip_relative && likely(ctxt->memopp))
                ctxt->memopp->addr.mem.ea = address_mask(ctxt,
                                        ctxt->memopp->addr.mem.ea + ctxt->_eip);
 
index c7220ba94aa776dceb3db4413ea9dec4ebace324..6e219e5c07d27c5dc41786953b1114b1e475e346 100644 (file)
@@ -94,7 +94,7 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
 static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
 {
        ioapic->rtc_status.pending_eoi = 0;
-       bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPUS);
+       bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPU_ID);
 }
 
 static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);
@@ -594,7 +594,7 @@ static void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
        ioapic->irr = 0;
        ioapic->irr_delivered = 0;
        ioapic->id = 0;
-       memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS);
+       memset(ioapic->irq_eoi, 0x00, sizeof(ioapic->irq_eoi));
        rtc_irq_eoi_tracking_reset(ioapic);
 }
 
index 7d2692a4965756143825d65d37688837d82aaca2..1cc6e54436dbaa71e4a68943456b9beaceec00f6 100644 (file)
@@ -42,13 +42,13 @@ struct kvm_vcpu;
 
 struct dest_map {
        /* vcpu bitmap where IRQ has been sent */
-       DECLARE_BITMAP(map, KVM_MAX_VCPUS);
+       DECLARE_BITMAP(map, KVM_MAX_VCPU_ID);
 
        /*
         * Vector sent to a given vcpu, only valid when
         * the vcpu's bit in map is set
         */
-       u8 vectors[KVM_MAX_VCPUS];
+       u8 vectors[KVM_MAX_VCPU_ID];
 };
 
 
index 25810b144b58d979c5ba9355fc7b0907494f5869..6c0191615f23a34bae5c0972a20025cf5b695af9 100644 (file)
@@ -41,6 +41,15 @@ static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
                           bool line_status)
 {
        struct kvm_pic *pic = pic_irqchip(kvm);
+
+       /*
+        * XXX: rejecting pic routes when pic isn't in use would be better,
+        * but the default routing table is installed while kvm->arch.vpic is
+        * NULL and KVM_CREATE_IRQCHIP can race with KVM_IRQ_LINE.
+        */
+       if (!pic)
+               return -1;
+
        return kvm_pic_set_irq(pic, e->irqchip.pin, irq_source_id, level);
 }
 
@@ -49,6 +58,10 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
                              bool line_status)
 {
        struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+
+       if (!ioapic)
+               return -1;
+
        return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, irq_source_id, level,
                                line_status);
 }
@@ -156,6 +169,16 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
 }
 
 
+static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
+                   struct kvm *kvm, int irq_source_id, int level,
+                   bool line_status)
+{
+       if (!level)
+               return -1;
+
+       return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
+}
+
 int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
                              struct kvm *kvm, int irq_source_id, int level,
                              bool line_status)
@@ -163,18 +186,26 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
        struct kvm_lapic_irq irq;
        int r;
 
-       if (unlikely(e->type != KVM_IRQ_ROUTING_MSI))
-               return -EWOULDBLOCK;
+       switch (e->type) {
+       case KVM_IRQ_ROUTING_HV_SINT:
+               return kvm_hv_set_sint(e, kvm, irq_source_id, level,
+                                      line_status);
 
-       if (kvm_msi_route_invalid(kvm, e))
-               return -EINVAL;
+       case KVM_IRQ_ROUTING_MSI:
+               if (kvm_msi_route_invalid(kvm, e))
+                       return -EINVAL;
 
-       kvm_set_msi_irq(kvm, e, &irq);
+               kvm_set_msi_irq(kvm, e, &irq);
 
-       if (kvm_irq_delivery_to_apic_fast(kvm, NULL, &irq, &r, NULL))
-               return r;
-       else
-               return -EWOULDBLOCK;
+               if (kvm_irq_delivery_to_apic_fast(kvm, NULL, &irq, &r, NULL))
+                       return r;
+               break;
+
+       default:
+               break;
+       }
+
+       return -EWOULDBLOCK;
 }
 
 int kvm_request_irq_source_id(struct kvm *kvm)
@@ -254,16 +285,6 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
        srcu_read_unlock(&kvm->irq_srcu, idx);
 }
 
-static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
-                   struct kvm *kvm, int irq_source_id, int level,
-                   bool line_status)
-{
-       if (!level)
-               return -1;
-
-       return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
-}
-
 int kvm_set_routing_entry(struct kvm *kvm,
                          struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue)
@@ -423,18 +444,6 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
        srcu_read_unlock(&kvm->irq_srcu, idx);
 }
 
-int kvm_arch_set_irq(struct kvm_kernel_irq_routing_entry *irq, struct kvm *kvm,
-                    int irq_source_id, int level, bool line_status)
-{
-       switch (irq->type) {
-       case KVM_IRQ_ROUTING_HV_SINT:
-               return kvm_hv_set_sint(irq, kvm, irq_source_id, level,
-                                      line_status);
-       default:
-               return -EWOULDBLOCK;
-       }
-}
-
 void kvm_arch_irq_routing_update(struct kvm *kvm)
 {
        kvm_hv_irq_routing_update(kvm);
index 23b99f3053825d40c6d697cf8c58dfb4ae941208..6f69340f9fa31496cf9ec8d91f69a5fc0b550ff6 100644 (file)
@@ -138,7 +138,7 @@ static inline bool kvm_apic_map_get_logical_dest(struct kvm_apic_map *map,
                *mask = dest_id & 0xff;
                return true;
        case KVM_APIC_MODE_XAPIC_CLUSTER:
-               *cluster = map->xapic_cluster_map[dest_id >> 4];
+               *cluster = map->xapic_cluster_map[(dest_id >> 4) & 0xf];
                *mask = dest_id & 0xf;
                return true;
        default:
index f8157a36ab099a2d3336ef422208b5f078154064..8ca1eca5038d5ce50f6376393abb83df79c4524f 100644 (file)
@@ -1138,21 +1138,6 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
        mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
 }
 
-static void svm_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       svm->vmcb->control.tsc_offset += adjustment;
-       if (is_guest_mode(vcpu))
-               svm->nested.hsave->control.tsc_offset += adjustment;
-       else
-               trace_kvm_write_tsc_offset(vcpu->vcpu_id,
-                                    svm->vmcb->control.tsc_offset - adjustment,
-                                    svm->vmcb->control.tsc_offset);
-
-       mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
-}
-
 static void avic_init_vmcb(struct vcpu_svm *svm)
 {
        struct vmcb *vmcb = svm->vmcb;
@@ -3449,12 +3434,6 @@ static int cr8_write_interception(struct vcpu_svm *svm)
        return 0;
 }
 
-static u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
-{
-       struct vmcb *vmcb = get_host_vmcb(to_svm(vcpu));
-       return vmcb->control.tsc_offset + host_tsc;
-}
-
 static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -5422,8 +5401,6 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .has_wbinvd_exit = svm_has_wbinvd_exit,
 
        .write_tsc_offset = svm_write_tsc_offset,
-       .adjust_tsc_offset_guest = svm_adjust_tsc_offset_guest,
-       .read_l1_tsc = svm_read_l1_tsc,
 
        .set_tdp_cr3 = set_tdp_cr3,
 
index cf1b16dbc98a90d4035a480362a549f299faf55f..5382b82462fcba28fed9a5064776cfb527e8eaa3 100644 (file)
@@ -187,6 +187,7 @@ struct vmcs {
  */
 struct loaded_vmcs {
        struct vmcs *vmcs;
+       struct vmcs *shadow_vmcs;
        int cpu;
        int launched;
        struct list_head loaded_vmcss_on_cpu_link;
@@ -411,7 +412,6 @@ struct nested_vmx {
         * memory during VMXOFF, VMCLEAR, VMPTRLD.
         */
        struct vmcs12 *cached_vmcs12;
-       struct vmcs *current_shadow_vmcs;
        /*
         * Indicates if the shadow vmcs must be updated with the
         * data hold by vmcs12
@@ -421,7 +421,6 @@ struct nested_vmx {
        /* vmcs02_list cache of VMCSs recently used to run L2 guests */
        struct list_head vmcs02_pool;
        int vmcs02_num;
-       u64 vmcs01_tsc_offset;
        bool change_vmcs01_virtual_x2apic_mode;
        /* L2 must run next, and mustn't decide to exit to L1. */
        bool nested_run_pending;
@@ -1419,6 +1418,8 @@ static void vmcs_clear(struct vmcs *vmcs)
 static inline void loaded_vmcs_init(struct loaded_vmcs *loaded_vmcs)
 {
        vmcs_clear(loaded_vmcs->vmcs);
+       if (loaded_vmcs->shadow_vmcs && loaded_vmcs->launched)
+               vmcs_clear(loaded_vmcs->shadow_vmcs);
        loaded_vmcs->cpu = -1;
        loaded_vmcs->launched = 0;
 }
@@ -2604,20 +2605,6 @@ static u64 guest_read_tsc(struct kvm_vcpu *vcpu)
        return kvm_scale_tsc(vcpu, host_tsc) + tsc_offset;
 }
 
-/*
- * Like guest_read_tsc, but always returns L1's notion of the timestamp
- * counter, even if a nested guest (L2) is currently running.
- */
-static u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
-{
-       u64 tsc_offset;
-
-       tsc_offset = is_guest_mode(vcpu) ?
-               to_vmx(vcpu)->nested.vmcs01_tsc_offset :
-               vmcs_read64(TSC_OFFSET);
-       return host_tsc + tsc_offset;
-}
-
 /*
  * writes 'offset' into guest's timestamp counter offset register
  */
@@ -2631,7 +2618,6 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
                 * to the newly set TSC to get L2's TSC.
                 */
                struct vmcs12 *vmcs12;
-               to_vmx(vcpu)->nested.vmcs01_tsc_offset = offset;
                /* recalculate vmcs02.TSC_OFFSET: */
                vmcs12 = get_vmcs12(vcpu);
                vmcs_write64(TSC_OFFSET, offset +
@@ -2644,19 +2630,6 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
        }
 }
 
-static void vmx_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment)
-{
-       u64 offset = vmcs_read64(TSC_OFFSET);
-
-       vmcs_write64(TSC_OFFSET, offset + adjustment);
-       if (is_guest_mode(vcpu)) {
-               /* Even when running L2, the adjustment needs to apply to L1 */
-               to_vmx(vcpu)->nested.vmcs01_tsc_offset += adjustment;
-       } else
-               trace_kvm_write_tsc_offset(vcpu->vcpu_id, offset,
-                                          offset + adjustment);
-}
-
 static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 1, 0);
@@ -3562,6 +3535,7 @@ static void free_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
        loaded_vmcs_clear(loaded_vmcs);
        free_vmcs(loaded_vmcs->vmcs);
        loaded_vmcs->vmcs = NULL;
+       WARN_ON(loaded_vmcs->shadow_vmcs != NULL);
 }
 
 static void free_kvm_area(void)
@@ -6696,6 +6670,7 @@ static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx)
        if (!item)
                return NULL;
        item->vmcs02.vmcs = alloc_vmcs();
+       item->vmcs02.shadow_vmcs = NULL;
        if (!item->vmcs02.vmcs) {
                kfree(item);
                return NULL;
@@ -7072,7 +7047,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
                shadow_vmcs->revision_id |= (1u << 31);
                /* init shadow vmcs */
                vmcs_clear(shadow_vmcs);
-               vmx->nested.current_shadow_vmcs = shadow_vmcs;
+               vmx->vmcs01.shadow_vmcs = shadow_vmcs;
        }
 
        INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
@@ -7174,8 +7149,11 @@ static void free_nested(struct vcpu_vmx *vmx)
                free_page((unsigned long)vmx->nested.msr_bitmap);
                vmx->nested.msr_bitmap = NULL;
        }
-       if (enable_shadow_vmcs)
-               free_vmcs(vmx->nested.current_shadow_vmcs);
+       if (enable_shadow_vmcs) {
+               vmcs_clear(vmx->vmcs01.shadow_vmcs);
+               free_vmcs(vmx->vmcs01.shadow_vmcs);
+               vmx->vmcs01.shadow_vmcs = NULL;
+       }
        kfree(vmx->nested.cached_vmcs12);
        /* Unpin physical memory we referred to in current vmcs02 */
        if (vmx->nested.apic_access_page) {
@@ -7352,7 +7330,7 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
        int i;
        unsigned long field;
        u64 field_value;
-       struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
+       struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
        const unsigned long *fields = shadow_read_write_fields;
        const int num_fields = max_shadow_read_write_fields;
 
@@ -7401,7 +7379,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
        int i, q;
        unsigned long field;
        u64 field_value = 0;
-       struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
+       struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
 
        vmcs_load(shadow_vmcs);
 
@@ -7591,7 +7569,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
                        vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
                                      SECONDARY_EXEC_SHADOW_VMCS);
                        vmcs_write64(VMCS_LINK_POINTER,
-                                    __pa(vmx->nested.current_shadow_vmcs));
+                                    __pa(vmx->vmcs01.shadow_vmcs));
                        vmx->nested.sync_shadow_vmcs = true;
                }
        }
@@ -7659,7 +7637,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
 
        types = (vmx->nested.nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6;
 
-       if (!(types & (1UL << type))) {
+       if (type >= 32 || !(types & (1 << type))) {
                nested_vmx_failValid(vcpu,
                                VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
                skip_emulated_instruction(vcpu);
@@ -7722,7 +7700,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
 
        types = (vmx->nested.nested_vmx_vpid_caps >> 8) & 0x7;
 
-       if (!(types & (1UL << type))) {
+       if (type >= 32 || !(types & (1 << type))) {
                nested_vmx_failValid(vcpu,
                        VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
                skip_emulated_instruction(vcpu);
@@ -9156,6 +9134,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 
        vmx->loaded_vmcs = &vmx->vmcs01;
        vmx->loaded_vmcs->vmcs = alloc_vmcs();
+       vmx->loaded_vmcs->shadow_vmcs = NULL;
        if (!vmx->loaded_vmcs->vmcs)
                goto free_msrs;
        if (!vmm_exclusive)
@@ -10061,9 +10040,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 
        if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
                vmcs_write64(TSC_OFFSET,
-                       vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset);
+                       vcpu->arch.tsc_offset + vmcs12->tsc_offset);
        else
-               vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
+               vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
        if (kvm_has_tsc_control)
                decache_tsc_multiplier(vmx);
 
@@ -10293,8 +10272,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
 
        enter_guest_mode(vcpu);
 
-       vmx->nested.vmcs01_tsc_offset = vmcs_read64(TSC_OFFSET);
-
        if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
                vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
 
@@ -10818,7 +10795,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
        load_vmcs12_host_state(vcpu, vmcs12);
 
        /* Update any VMCS fields that might have changed while L2 ran */
-       vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
+       vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
        if (vmx->hv_deadline_tsc == -1)
                vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
                                PIN_BASED_VMX_PREEMPTION_TIMER);
@@ -11339,8 +11316,6 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
        .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
 
        .write_tsc_offset = vmx_write_tsc_offset,
-       .adjust_tsc_offset_guest = vmx_adjust_tsc_offset_guest,
-       .read_l1_tsc = vmx_read_l1_tsc,
 
        .set_tdp_cr3 = vmx_set_cr3,
 
index 6c633de84dd7339637e24604952fb4d2c5180562..04c5d96b1d678a6eeec993b71efb93f509496bdf 100644 (file)
@@ -210,7 +210,18 @@ static void kvm_on_user_return(struct user_return_notifier *urn)
        struct kvm_shared_msrs *locals
                = container_of(urn, struct kvm_shared_msrs, urn);
        struct kvm_shared_msr_values *values;
+       unsigned long flags;
 
+       /*
+        * Disabling irqs at this point since the following code could be
+        * interrupted and executed through kvm_arch_hardware_disable()
+        */
+       local_irq_save(flags);
+       if (locals->registered) {
+               locals->registered = false;
+               user_return_notifier_unregister(urn);
+       }
+       local_irq_restore(flags);
        for (slot = 0; slot < shared_msrs_global.nr; ++slot) {
                values = &locals->values[slot];
                if (values->host != values->curr) {
@@ -218,8 +229,6 @@ static void kvm_on_user_return(struct user_return_notifier *urn)
                        values->curr = values->host;
                }
        }
-       locals->registered = false;
-       user_return_notifier_unregister(urn);
 }
 
 static void shared_msr_update(unsigned slot, u32 msr)
@@ -1409,7 +1418,7 @@ static u64 kvm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
 
 u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
 {
-       return kvm_x86_ops->read_l1_tsc(vcpu, kvm_scale_tsc(vcpu, host_tsc));
+       return vcpu->arch.tsc_offset + kvm_scale_tsc(vcpu, host_tsc);
 }
 EXPORT_SYMBOL_GPL(kvm_read_l1_tsc);
 
@@ -1547,7 +1556,7 @@ EXPORT_SYMBOL_GPL(kvm_write_tsc);
 static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
                                           s64 adjustment)
 {
-       kvm_x86_ops->adjust_tsc_offset_guest(vcpu, adjustment);
+       kvm_vcpu_write_tsc_offset(vcpu, vcpu->arch.tsc_offset + adjustment);
 }
 
 static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
@@ -1555,7 +1564,7 @@ static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
        if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio)
                WARN_ON(adjustment < 0);
        adjustment = kvm_scale_tsc(vcpu, (u64) adjustment);
-       kvm_x86_ops->adjust_tsc_offset_guest(vcpu, adjustment);
+       adjust_tsc_offset_guest(vcpu, adjustment);
 }
 
 #ifdef CONFIG_X86_64
@@ -1724,18 +1733,23 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)
 
 static u64 __get_kvmclock_ns(struct kvm *kvm)
 {
-       struct kvm_vcpu *vcpu = kvm_get_vcpu(kvm, 0);
        struct kvm_arch *ka = &kvm->arch;
-       s64 ns;
+       struct pvclock_vcpu_time_info hv_clock;
 
-       if (vcpu->arch.hv_clock.flags & PVCLOCK_TSC_STABLE_BIT) {
-               u64 tsc = kvm_read_l1_tsc(vcpu, rdtsc());
-               ns = __pvclock_read_cycles(&vcpu->arch.hv_clock, tsc);
-       } else {
-               ns = ktime_get_boot_ns() + ka->kvmclock_offset;
+       spin_lock(&ka->pvclock_gtod_sync_lock);
+       if (!ka->use_master_clock) {
+               spin_unlock(&ka->pvclock_gtod_sync_lock);
+               return ktime_get_boot_ns() + ka->kvmclock_offset;
        }
 
-       return ns;
+       hv_clock.tsc_timestamp = ka->master_cycle_now;
+       hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
+       spin_unlock(&ka->pvclock_gtod_sync_lock);
+
+       kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL,
+                          &hv_clock.tsc_shift,
+                          &hv_clock.tsc_to_system_mul);
+       return __pvclock_read_cycles(&hv_clock, rdtsc());
 }
 
 u64 get_kvmclock_ns(struct kvm *kvm)
@@ -2262,7 +2276,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                /* Drop writes to this legacy MSR -- see rdmsr
                 * counterpart for further detail.
                 */
-               vcpu_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data);
+               vcpu_unimpl(vcpu, "ignored wrmsr: 0x%x data 0x%llx\n", msr, data);
                break;
        case MSR_AMD64_OSVW_ID_LENGTH:
                if (!guest_cpuid_has_osvw(vcpu))
@@ -2280,11 +2294,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                if (kvm_pmu_is_valid_msr(vcpu, msr))
                        return kvm_pmu_set_msr(vcpu, msr_info);
                if (!ignore_msrs) {
-                       vcpu_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
+                       vcpu_unimpl(vcpu, "unhandled wrmsr: 0x%x data 0x%llx\n",
                                    msr, data);
                        return 1;
                } else {
-                       vcpu_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n",
+                       vcpu_unimpl(vcpu, "ignored wrmsr: 0x%x data 0x%llx\n",
                                    msr, data);
                        break;
                }
@@ -2596,7 +2610,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_PIT_STATE2:
        case KVM_CAP_SET_IDENTITY_MAP_ADDR:
        case KVM_CAP_XEN_HVM:
-       case KVM_CAP_ADJUST_CLOCK:
        case KVM_CAP_VCPU_EVENTS:
        case KVM_CAP_HYPERV:
        case KVM_CAP_HYPERV_VAPIC:
@@ -2623,6 +2636,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 #endif
                r = 1;
                break;
+       case KVM_CAP_ADJUST_CLOCK:
+               r = KVM_CLOCK_TSC_STABLE;
+               break;
        case KVM_CAP_X86_SMM:
                /* SMBASE is usually relocated above 1M on modern chipsets,
                 * and SMM handlers might indeed rely on 4G segment limits,
@@ -3415,6 +3431,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        };
        case KVM_SET_VAPIC_ADDR: {
                struct kvm_vapic_addr va;
+               int idx;
 
                r = -EINVAL;
                if (!lapic_in_kernel(vcpu))
@@ -3422,7 +3439,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = -EFAULT;
                if (copy_from_user(&va, argp, sizeof va))
                        goto out;
+               idx = srcu_read_lock(&vcpu->kvm->srcu);
                r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
+               srcu_read_unlock(&vcpu->kvm->srcu, idx);
                break;
        }
        case KVM_X86_SETUP_MCE: {
@@ -4103,9 +4122,11 @@ long kvm_arch_vm_ioctl(struct file *filp,
                struct kvm_clock_data user_ns;
                u64 now_ns;
 
-               now_ns = get_kvmclock_ns(kvm);
+               local_irq_disable();
+               now_ns = __get_kvmclock_ns(kvm);
                user_ns.clock = now_ns;
-               user_ns.flags = 0;
+               user_ns.flags = kvm->arch.use_master_clock ? KVM_CLOCK_TSC_STABLE : 0;
+               local_irq_enable();
                memset(&user_ns.pad, 0, sizeof(user_ns.pad));
 
                r = -EFAULT;
@@ -5733,13 +5754,13 @@ static int kvmclock_cpu_online(unsigned int cpu)
 
 static void kvm_timer_init(void)
 {
-       int cpu;
-
        max_tsc_khz = tsc_khz;
 
        if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
 #ifdef CONFIG_CPU_FREQ
                struct cpufreq_policy policy;
+               int cpu;
+
                memset(&policy, 0, sizeof(policy));
                cpu = get_cpu();
                cpufreq_get_policy(&policy, cpu);
@@ -7410,10 +7431,12 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 {
+       void *wbinvd_dirty_mask = vcpu->arch.wbinvd_dirty_mask;
+
        kvmclock_reset(vcpu);
 
-       free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
        kvm_x86_ops->vcpu_free(vcpu);
+       free_cpumask_var(wbinvd_dirty_mask);
 }
 
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
index 79ae939970d3f49065fa4f0ed3dcc6d769ddf48a..fcd06f7526de31a6cd429e6d800ea93fcac294f9 100644 (file)
@@ -135,7 +135,12 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
        if (early_recursion_flag > 2)
                goto halt_loop;
 
-       if (regs->cs != __KERNEL_CS)
+       /*
+        * Old CPUs leave the high bits of CS on the stack
+        * undefined.  I'm not sure which CPUs do this, but at least
+        * the 486 DX works this way.
+        */
+       if ((regs->cs & 0xFFFF) != __KERNEL_CS)
                goto fail;
 
        /*
index b8b6a60b32cf47837070518bd44d4c4742910697..0d4fb3ebbbac9872aaaf26514211ae543a253299 100644 (file)
@@ -435,7 +435,7 @@ slow_irqon:
 
                ret = get_user_pages_unlocked(start,
                                              (end - start) >> PAGE_SHIFT,
-                                             write, 0, pages);
+                                             pages, write ? FOLL_WRITE : 0);
 
                /* Have to be a bit careful with return values */
                if (nr > 0) {
index ddd2661c4502922a63fbcd169615d34dddd6fcae..887e57182716828b7f4f4946fe7145d106ec5bea 100644 (file)
@@ -104,10 +104,10 @@ void __init kernel_randomize_memory(void)
         * consistent with the vaddr_start/vaddr_end variables.
         */
        BUILD_BUG_ON(vaddr_start >= vaddr_end);
-       BUILD_BUG_ON(config_enabled(CONFIG_X86_ESPFIX64) &&
+       BUILD_BUG_ON(IS_ENABLED(CONFIG_X86_ESPFIX64) &&
                     vaddr_end >= EFI_VA_START);
-       BUILD_BUG_ON((config_enabled(CONFIG_X86_ESPFIX64) ||
-                     config_enabled(CONFIG_EFI)) &&
+       BUILD_BUG_ON((IS_ENABLED(CONFIG_X86_ESPFIX64) ||
+                     IS_ENABLED(CONFIG_EFI)) &&
                     vaddr_end >= __START_KERNEL_map);
        BUILD_BUG_ON(vaddr_end > __START_KERNEL_map);
 
index 80476878eb4ca5c8ad56340bb52b2423995a7867..e4f800999b32dc94d5ba1a1283591649a818fbb7 100644 (file)
@@ -544,10 +544,9 @@ static int mpx_resolve_fault(long __user *addr, int write)
 {
        long gup_ret;
        int nr_pages = 1;
-       int force = 0;
 
-       gup_ret = get_user_pages((unsigned long)addr, nr_pages, write,
-                       force, NULL, NULL);
+       gup_ret = get_user_pages((unsigned long)addr, nr_pages,
+                       write ? FOLL_WRITE : 0, NULL, NULL);
        /*
         * get_user_pages() returns number of pages gotten.
         * 0 means we failed to fault in and get anything,
index 170cc4ff057b398382bef3dd635d6a9115460d88..83e701f160a9128dc72316376d8b6a66233e223c 100644 (file)
@@ -730,6 +730,20 @@ void io_free_memtype(resource_size_t start, resource_size_t end)
        free_memtype(start, end);
 }
 
+int arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size)
+{
+       enum page_cache_mode type = _PAGE_CACHE_MODE_WC;
+
+       return io_reserve_memtype(start, start + size, &type);
+}
+EXPORT_SYMBOL(arch_io_reserve_memtype_wc);
+
+void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
+{
+       io_free_memtype(start, start + size);
+}
+EXPORT_SYMBOL(arch_io_free_memtype_wc);
+
 pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
                                unsigned long size, pgprot_t vma_prot)
 {
index bf99aa7005eb3eda505893352be0bd6a02f312b1..936a488d6cf6df3c2aadbbdbc036b8eb06701cb0 100644 (file)
@@ -861,7 +861,7 @@ static void __init __efi_enter_virtual_mode(void)
        int count = 0, pg_shift = 0;
        void *new_memmap = NULL;
        efi_status_t status;
-       phys_addr_t pa;
+       unsigned long pa;
 
        efi.systab = NULL;
 
index 58b0f801f66f97212fb9904c77d88ad44c2703de..319148bd4b05091d24576a7535b10aad7bec0c2d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/io.h>
 #include <linux/reboot.h>
 #include <linux/slab.h>
+#include <linux/ucs2_string.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -211,6 +212,35 @@ void efi_sync_low_kernel_mappings(void)
        memcpy(pud_efi, pud_k, sizeof(pud_t) * num_entries);
 }
 
+/*
+ * Wrapper for slow_virt_to_phys() that handles NULL addresses.
+ */
+static inline phys_addr_t
+virt_to_phys_or_null_size(void *va, unsigned long size)
+{
+       bool bad_size;
+
+       if (!va)
+               return 0;
+
+       if (virt_addr_valid(va))
+               return virt_to_phys(va);
+
+       /*
+        * A fully aligned variable on the stack is guaranteed not to
+        * cross a page bounary. Try to catch strings on the stack by
+        * checking that 'size' is a power of two.
+        */
+       bad_size = size > PAGE_SIZE || !is_power_of_2(size);
+
+       WARN_ON(!IS_ALIGNED((unsigned long)va, size) || bad_size);
+
+       return slow_virt_to_phys(va);
+}
+
+#define virt_to_phys_or_null(addr)                             \
+       virt_to_phys_or_null_size((addr), sizeof(*(addr)))
+
 int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 {
        unsigned long pfn, text;
@@ -494,8 +524,8 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 
        spin_lock(&rtc_lock);
 
-       phys_tm = virt_to_phys(tm);
-       phys_tc = virt_to_phys(tc);
+       phys_tm = virt_to_phys_or_null(tm);
+       phys_tc = virt_to_phys_or_null(tc);
 
        status = efi_thunk(get_time, phys_tm, phys_tc);
 
@@ -511,7 +541,7 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm)
 
        spin_lock(&rtc_lock);
 
-       phys_tm = virt_to_phys(tm);
+       phys_tm = virt_to_phys_or_null(tm);
 
        status = efi_thunk(set_time, phys_tm);
 
@@ -529,9 +559,9 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
 
        spin_lock(&rtc_lock);
 
-       phys_enabled = virt_to_phys(enabled);
-       phys_pending = virt_to_phys(pending);
-       phys_tm = virt_to_phys(tm);
+       phys_enabled = virt_to_phys_or_null(enabled);
+       phys_pending = virt_to_phys_or_null(pending);
+       phys_tm = virt_to_phys_or_null(tm);
 
        status = efi_thunk(get_wakeup_time, phys_enabled,
                             phys_pending, phys_tm);
@@ -549,7 +579,7 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
 
        spin_lock(&rtc_lock);
 
-       phys_tm = virt_to_phys(tm);
+       phys_tm = virt_to_phys_or_null(tm);
 
        status = efi_thunk(set_wakeup_time, enabled, phys_tm);
 
@@ -558,6 +588,10 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
        return status;
 }
 
+static unsigned long efi_name_size(efi_char16_t *name)
+{
+       return ucs2_strsize(name, EFI_VAR_NAME_LEN) + 1;
+}
 
 static efi_status_t
 efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
@@ -567,11 +601,11 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
        u32 phys_name, phys_vendor, phys_attr;
        u32 phys_data_size, phys_data;
 
-       phys_data_size = virt_to_phys(data_size);
-       phys_vendor = virt_to_phys(vendor);
-       phys_name = virt_to_phys(name);
-       phys_attr = virt_to_phys(attr);
-       phys_data = virt_to_phys(data);
+       phys_data_size = virt_to_phys_or_null(data_size);
+       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
+       phys_attr = virt_to_phys_or_null(attr);
+       phys_data = virt_to_phys_or_null_size(data, *data_size);
 
        status = efi_thunk(get_variable, phys_name, phys_vendor,
                           phys_attr, phys_data_size, phys_data);
@@ -586,9 +620,9 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
        u32 phys_name, phys_vendor, phys_data;
        efi_status_t status;
 
-       phys_name = virt_to_phys(name);
-       phys_vendor = virt_to_phys(vendor);
-       phys_data = virt_to_phys(data);
+       phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
+       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_data = virt_to_phys_or_null_size(data, data_size);
 
        /* If data_size is > sizeof(u32) we've got problems */
        status = efi_thunk(set_variable, phys_name, phys_vendor,
@@ -605,9 +639,9 @@ efi_thunk_get_next_variable(unsigned long *name_size,
        efi_status_t status;
        u32 phys_name_size, phys_name, phys_vendor;
 
-       phys_name_size = virt_to_phys(name_size);
-       phys_vendor = virt_to_phys(vendor);
-       phys_name = virt_to_phys(name);
+       phys_name_size = virt_to_phys_or_null(name_size);
+       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_name = virt_to_phys_or_null_size(name, *name_size);
 
        status = efi_thunk(get_next_variable, phys_name_size,
                           phys_name, phys_vendor);
@@ -621,7 +655,7 @@ efi_thunk_get_next_high_mono_count(u32 *count)
        efi_status_t status;
        u32 phys_count;
 
-       phys_count = virt_to_phys(count);
+       phys_count = virt_to_phys_or_null(count);
        status = efi_thunk(get_next_high_mono_count, phys_count);
 
        return status;
@@ -633,7 +667,7 @@ efi_thunk_reset_system(int reset_type, efi_status_t status,
 {
        u32 phys_data;
 
-       phys_data = virt_to_phys(data);
+       phys_data = virt_to_phys_or_null_size(data, data_size);
 
        efi_thunk(reset_system, reset_type, status, data_size, phys_data);
 }
@@ -661,9 +695,9 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
        if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
                return EFI_UNSUPPORTED;
 
-       phys_storage = virt_to_phys(storage_space);
-       phys_remaining = virt_to_phys(remaining_space);
-       phys_max = virt_to_phys(max_variable_size);
+       phys_storage = virt_to_phys_or_null(storage_space);
+       phys_remaining = virt_to_phys_or_null(remaining_space);
+       phys_max = virt_to_phys_or_null(max_variable_size);
 
        status = efi_thunk(query_variable_info, attr, phys_storage,
                           phys_remaining, phys_max);
index 429d08be7848a2df6334aef7e5e2c4e79e4b6d4a..dd6cfa4ad3ac35713da9c93951bd65bd70106a58 100644 (file)
@@ -28,4 +28,4 @@ obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_pcal9555a.o
 obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_tca6416.o
 # MISC Devices
 obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o
-obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_wdt.o
+obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_mrfld_wdt.o
similarity index 65%
rename from arch/x86/platform/intel-mid/device_libs/platform_wdt.c
rename to arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c
index de734134bc8d2e1733fb831a32cdbfd8fcf80ed5..3f1f1c77d0903a9a4e435979586d026b30c66741 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * platform_wdt.c: Watchdog platform library file
+ * Intel Merrifield watchdog platform device library file
  *
  * (C) Copyright 2014 Intel Corporation
  * Author: David Cohen <david.a.cohen@linux.intel.com>
@@ -14,7 +14,9 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/intel-mid_wdt.h>
+
 #include <asm/intel-mid.h>
+#include <asm/intel_scu_ipc.h>
 #include <asm/io_apic.h>
 
 #define TANGIER_EXT_TIMER0_MSI 15
@@ -50,14 +52,34 @@ static struct intel_mid_wdt_pdata tangier_pdata = {
        .probe = tangier_probe,
 };
 
-static int __init register_mid_wdt(void)
+static int wdt_scu_status_change(struct notifier_block *nb,
+                                unsigned long code, void *data)
 {
-       if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
-               wdt_dev.dev.platform_data = &tangier_pdata;
-               return platform_device_register(&wdt_dev);
+       if (code == SCU_DOWN) {
+               platform_device_unregister(&wdt_dev);
+               return 0;
        }
 
-       return -ENODEV;
+       return platform_device_register(&wdt_dev);
 }
 
+static struct notifier_block wdt_scu_notifier = {
+       .notifier_call  = wdt_scu_status_change,
+};
+
+static int __init register_mid_wdt(void)
+{
+       if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER)
+               return -ENODEV;
+
+       wdt_dev.dev.platform_data = &tangier_pdata;
+
+       /*
+        * We need to be sure that the SCU IPC is ready before watchdog device
+        * can be registered:
+        */
+       intel_scu_notifier_add(&wdt_scu_notifier);
+
+       return 0;
+}
 rootfs_initcall(register_mid_wdt);
index 5d3b45ad1c034d4ca922ccdd10ad7d2edb565384..67375dda451c1bec9fe900899dee5a5898882281 100644 (file)
@@ -272,6 +272,25 @@ int intel_mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state)
 }
 EXPORT_SYMBOL_GPL(intel_mid_pci_set_power_state);
 
+pci_power_t intel_mid_pci_get_power_state(struct pci_dev *pdev)
+{
+       struct mid_pwr *pwr = midpwr;
+       int id, reg, bit;
+       u32 power;
+
+       if (!pwr || !pwr->available)
+               return PCI_UNKNOWN;
+
+       id = intel_mid_pwr_get_lss_id(pdev);
+       if (id < 0)
+               return PCI_UNKNOWN;
+
+       reg = (id * LSS_PWS_BITS) / 32;
+       bit = (id * LSS_PWS_BITS) % 32;
+       power = mid_pwr_get_state(pwr, reg);
+       return (__force pci_power_t)((power >> bit) & 3);
+}
+
 void intel_mid_pwr_power_off(void)
 {
        struct mid_pwr *pwr = midpwr;
index 55130846ac87afe11d50e7bdbcf77b77827838b0..c0533fbc39e3a4e9f56575dffe6d0de3a4082706 100644 (file)
@@ -196,6 +196,7 @@ static int xo15_sci_remove(struct acpi_device *device)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int xo15_sci_resume(struct device *dev)
 {
        /* Enable all EC events */
@@ -207,6 +208,7 @@ static int xo15_sci_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(xo15_sci_pm, NULL, xo15_sci_resume);
 
index b4d5e95fe4dfea57c3d9bdcdfa2d35d46a48bc5d..4a6a5a26c58295e4245b09be21a658c3ddae86a2 100644 (file)
@@ -40,7 +40,15 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
                 */
                return BIOS_STATUS_UNIMPLEMENTED;
 
-       ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
+       /*
+        * If EFI_OLD_MEMMAP is set, we need to fall back to using our old EFI
+        * callback method, which uses efi_call() directly, with the kernel page tables:
+        */
+       if (unlikely(test_bit(EFI_OLD_MEMMAP, &efi.flags)))
+               ret = efi_call((void *)__va(tab->function), (u64)which, a1, a2, a3, a4, a5);
+       else
+               ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(uv_bios_call);
index ac58c1616408b515813403389f9d0c91bc19124c..555b9fa0ad43cbd4148b2fb268692d4b2de167c4 100644 (file)
@@ -16,6 +16,7 @@ KCOV_INSTRUMENT := n
 
 KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes -fno-zero-initialized-in-bss -fno-builtin -ffreestanding -c -MD -Os -mcmodel=large
 KBUILD_CFLAGS += -m$(BITS)
+KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
 
 $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
                $(call if_changed,ld)
index f59590645b68641e4de9da7278b6f1c07f2e3b82..1d23bf953a4a451033f2d25a08eab2eebd751b3f 100644 (file)
@@ -16,7 +16,7 @@
 #include <regex.h>
 #include <tools/le_byteshift.h>
 
-void die(char *fmt, ...);
+void die(char *fmt, ...) __attribute__((noreturn));
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
index 5766ead6fdb9679907c63aa78f8becccc8d9ecff..60a5a5a85505dd25305aea03d0850613e51ee791 100644 (file)
@@ -36,7 +36,8 @@ int is_syscall(unsigned long addr)
                 * slow, but that doesn't matter, since it will be called only
                 * in case of singlestepping, if copy_from_user failed.
                 */
-               n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
+               n = access_process_vm(current, addr, &instr, sizeof(instr),
+                               FOLL_FORCE);
                if (n != sizeof(instr)) {
                        printk(KERN_ERR "is_syscall : failed to read "
                               "instruction from 0x%lx\n", addr);
index 0b5c184dd5b3b80894c3db60ead6432ad20dca57..e30202b1716efb4243372d02e61f5f8269203419 100644 (file)
@@ -212,7 +212,8 @@ int is_syscall(unsigned long addr)
                 * slow, but that doesn't matter, since it will be called only
                 * in case of singlestepping, if copy_from_user failed.
                 */
-               n = access_process_vm(current, addr, &instr, sizeof(instr), 0);
+               n = access_process_vm(current, addr, &instr, sizeof(instr),
+                               FOLL_FORCE);
                if (n != sizeof(instr)) {
                        printk("is_syscall : failed to read instruction from "
                               "0x%lx\n", addr);
index c0fdd57da7aad477534b5e4d019ebe4e06e2df07..bdd85568540382ebe3b5683534fb2ab7144e39a3 100644 (file)
@@ -1837,6 +1837,7 @@ static void __init init_hvm_pv_info(void)
 
        xen_domain_type = XEN_HVM_DOMAIN;
 }
+#endif
 
 static int xen_cpu_up_prepare(unsigned int cpu)
 {
@@ -1887,6 +1888,7 @@ static int xen_cpu_up_online(unsigned int cpu)
        return 0;
 }
 
+#ifdef CONFIG_XEN_PVHVM
 #ifdef CONFIG_KEXEC_CORE
 static void xen_hvm_shutdown(void)
 {
index de9b14b2d348b84ea078e412d3d9f3883e444cb4..cd400af4a6b25597756cda04826278fea75ecf33 100644 (file)
@@ -767,7 +767,14 @@ __SYSCALL(346, sys_preadv2, 6)
 #define __NR_pwritev2                          347
 __SYSCALL(347, sys_pwritev2, 6)
 
-#define __NR_syscall_count                     348
+#define __NR_pkey_mprotect                     348
+__SYSCALL(348, sys_pkey_mprotect, 4)
+#define __NR_pkey_alloc                                349
+__SYSCALL(349, sys_pkey_alloc, 2)
+#define __NR_pkey_free                         350
+__SYSCALL(350, sys_pkey_free, 1)
+
+#define __NR_syscall_count                     351
 
 /*
  * sysxtensa syscall handler
index 9a5bcd0381a71e987b29499d194061af8a1b2d22..be81e69b25bc98e46514c46e4a5a030afb87ecca 100644 (file)
@@ -172,10 +172,11 @@ void __init time_init(void)
 {
        of_clk_init(NULL);
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
-       printk("Calibrating CPU frequency ");
+       pr_info("Calibrating CPU frequency ");
        calibrate_ccount();
-       printk("%d.%02d MHz\n", (int)ccount_freq/1000000,
-                       (int)(ccount_freq/10000)%100);
+       pr_cont("%d.%02d MHz\n",
+               (int)ccount_freq / 1000000,
+               (int)(ccount_freq / 10000) % 100);
 #else
        ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL;
 #endif
@@ -210,9 +211,8 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
 void calibrate_delay(void)
 {
        loops_per_jiffy = ccount_freq / HZ;
-       printk("Calibrating delay loop (skipped)... "
-              "%lu.%02lu BogoMIPS preset\n",
-              loops_per_jiffy/(1000000/HZ),
-              (loops_per_jiffy/(10000/HZ)) % 100);
+       pr_info("Calibrating delay loop (skipped)... %lu.%02lu BogoMIPS preset\n",
+               loops_per_jiffy / (1000000 / HZ),
+               (loops_per_jiffy / (10000 / HZ)) % 100);
 }
 #endif
index d02fc304b31c10ea9019172b8fd15d8aaea41bdc..ce37d5b899fead50d312f06ed3c3f3982309d294 100644 (file)
@@ -465,26 +465,25 @@ void show_regs(struct pt_regs * regs)
 
        for (i = 0; i < 16; i++) {
                if ((i % 8) == 0)
-                       printk(KERN_INFO "a%02d:", i);
-               printk(KERN_CONT " %08lx", regs->areg[i]);
+                       pr_info("a%02d:", i);
+               pr_cont(" %08lx", regs->areg[i]);
        }
-       printk(KERN_CONT "\n");
-
-       printk("pc: %08lx, ps: %08lx, depc: %08lx, excvaddr: %08lx\n",
-              regs->pc, regs->ps, regs->depc, regs->excvaddr);
-       printk("lbeg: %08lx, lend: %08lx lcount: %08lx, sar: %08lx\n",
-              regs->lbeg, regs->lend, regs->lcount, regs->sar);
+       pr_cont("\n");
+       pr_info("pc: %08lx, ps: %08lx, depc: %08lx, excvaddr: %08lx\n",
+               regs->pc, regs->ps, regs->depc, regs->excvaddr);
+       pr_info("lbeg: %08lx, lend: %08lx lcount: %08lx, sar: %08lx\n",
+               regs->lbeg, regs->lend, regs->lcount, regs->sar);
        if (user_mode(regs))
-               printk("wb: %08lx, ws: %08lx, wmask: %08lx, syscall: %ld\n",
-                      regs->windowbase, regs->windowstart, regs->wmask,
-                      regs->syscall);
+               pr_cont("wb: %08lx, ws: %08lx, wmask: %08lx, syscall: %ld\n",
+                       regs->windowbase, regs->windowstart, regs->wmask,
+                       regs->syscall);
 }
 
 static int show_trace_cb(struct stackframe *frame, void *data)
 {
        if (kernel_text_address(frame->pc)) {
-               printk(" [<%08lx>] ", frame->pc);
-               print_symbol("%s\n", frame->pc);
+               pr_cont(" [<%08lx>]", frame->pc);
+               print_symbol(" %s\n", frame->pc);
        }
        return 0;
 }
@@ -494,19 +493,13 @@ void show_trace(struct task_struct *task, unsigned long *sp)
        if (!sp)
                sp = stack_pointer(task);
 
-       printk("Call Trace:");
-#ifdef CONFIG_KALLSYMS
-       printk("\n");
-#endif
+       pr_info("Call Trace:\n");
        walk_stackframe(sp, show_trace_cb, NULL);
-       printk("\n");
+#ifndef CONFIG_KALLSYMS
+       pr_cont("\n");
+#endif
 }
 
-/*
- * This routine abuses get_user()/put_user() to reference pointers
- * with at least a bit of error checking ...
- */
-
 static int kstack_depth_to_print = 24;
 
 void show_stack(struct task_struct *task, unsigned long *sp)
@@ -518,52 +511,29 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                sp = stack_pointer(task);
        stack = sp;
 
-       printk("\nStack: ");
+       pr_info("Stack:\n");
 
        for (i = 0; i < kstack_depth_to_print; i++) {
                if (kstack_end(sp))
                        break;
-               if (i && ((i % 8) == 0))
-                       printk("\n       ");
-               printk("%08lx ", *sp++);
+               pr_cont(" %08lx", *sp++);
+               if (i % 8 == 7)
+                       pr_cont("\n");
        }
-       printk("\n");
        show_trace(task, stack);
 }
 
-void show_code(unsigned int *pc)
-{
-       long i;
-
-       printk("\nCode:");
-
-       for(i = -3 ; i < 6 ; i++) {
-               unsigned long insn;
-               if (__get_user(insn, pc + i)) {
-                       printk(" (Bad address in pc)\n");
-                       break;
-               }
-               printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>'));
-       }
-}
-
 DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
        static int die_counter;
-       int nl = 0;
 
        console_verbose();
        spin_lock_irq(&die_lock);
 
-       printk("%s: sig: %ld [#%d]\n", str, err, ++die_counter);
-#ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
-       nl = 1;
-#endif
-       if (nl)
-               printk("\n");
+       pr_info("%s: sig: %ld [#%d]%s\n", str, err, ++die_counter,
+               IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "");
        show_regs(regs);
        if (!user_mode(regs))
                show_stack(NULL, (unsigned long*)regs->areg[1]);
index 7be53cb1cc3cebf3e9f5c30e004f6f74b50bfdbf..6ebcef28231486ae2b9dcefadfe61412b2112f11 100644 (file)
@@ -133,6 +133,26 @@ retry:
 }
 EXPORT_SYMBOL_GPL(badblocks_check);
 
+static void badblocks_update_acked(struct badblocks *bb)
+{
+       u64 *p = bb->page;
+       int i;
+       bool unacked = false;
+
+       if (!bb->unacked_exist)
+               return;
+
+       for (i = 0; i < bb->count ; i++) {
+               if (!BB_ACK(p[i])) {
+                       unacked = true;
+                       break;
+               }
+       }
+
+       if (!unacked)
+               bb->unacked_exist = 0;
+}
+
 /**
  * badblocks_set() - Add a range of bad blocks to the table.
  * @bb:                the badblocks structure that holds all badblock information
@@ -294,6 +314,8 @@ int badblocks_set(struct badblocks *bb, sector_t s, int sectors,
        bb->changed = 1;
        if (!acknowledged)
                bb->unacked_exist = 1;
+       else
+               badblocks_update_acked(bb);
        write_sequnlock_irqrestore(&bb->lock, flags);
 
        return rv;
@@ -354,7 +376,8 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
                 * current range.  Earlier ranges could also overlap,
                 * but only this one can overlap the end of the range.
                 */
-               if (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) {
+               if ((BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) &&
+                   (BB_OFFSET(p[lo]) < target)) {
                        /* Partial overlap, leave the tail of this range */
                        int ack = BB_ACK(p[lo]);
                        sector_t a = BB_OFFSET(p[lo]);
@@ -377,7 +400,8 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
                        lo--;
                }
                while (lo >= 0 &&
-                      BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
+                      (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) &&
+                      (BB_OFFSET(p[lo]) < target)) {
                        /* This range does overlap */
                        if (BB_OFFSET(p[lo]) < s) {
                                /* Keep the early parts of this range. */
@@ -399,6 +423,7 @@ int badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
                }
        }
 
+       badblocks_update_acked(bb);
        bb->changed = 1;
 out:
        write_sequnlock_irq(&bb->lock);
index 6a14b68b91358bdd28d90fb5ab23100a77af31dd..3c882cbc75417d60bfa92c20f5da27aaaa86c4bf 100644 (file)
@@ -342,6 +342,34 @@ static void flush_data_end_io(struct request *rq, int error)
        struct request_queue *q = rq->q;
        struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL);
 
+       /*
+        * Updating q->in_flight[] here for making this tag usable
+        * early. Because in blk_queue_start_tag(),
+        * q->in_flight[BLK_RW_ASYNC] is used to limit async I/O and
+        * reserve tags for sync I/O.
+        *
+        * More importantly this way can avoid the following I/O
+        * deadlock:
+        *
+        * - suppose there are 40 fua requests comming to flush queue
+        *   and queue depth is 31
+        * - 30 rqs are scheduled then blk_queue_start_tag() can't alloc
+        *   tag for async I/O any more
+        * - all the 30 rqs are completed before FLUSH_PENDING_TIMEOUT
+        *   and flush_data_end_io() is called
+        * - the other rqs still can't go ahead if not updating
+        *   q->in_flight[BLK_RW_ASYNC] here, meantime these rqs
+        *   are held in flush data queue and make no progress of
+        *   handling post flush rq
+        * - only after the post flush rq is handled, all these rqs
+        *   can be completed
+        */
+
+       elv_completed_request(q, rq);
+
+       /* for avoiding double accounting */
+       rq->cmd_flags &= ~REQ_STARTED;
+
        /*
         * After populating an empty queue, kick it to avoid stall.  Read
         * the comment in flush_end_io().
index b8657fa8dc9af7b2f5fe7958693df063cc4c9019..27fd8d92892d47e3478d9bcf3e1294a8eb28da89 100644 (file)
@@ -118,6 +118,9 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        struct iov_iter i;
        int ret;
 
+       if (!iter_is_iovec(iter))
+               goto fail;
+
        if (map_data)
                copy = true;
        else if (iov_iter_alignment(iter) & align)
@@ -140,6 +143,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
 
 unmap_rq:
        __blk_rq_unmap_user(bio);
+fail:
        rq->bio = NULL;
        return -EINVAL;
 }
index ddc2eed6477146320073b061a61e15ebe4d587eb..f3d27a6dee09dfa48dd7b78bc024f4a9809e8f88 100644 (file)
@@ -1217,9 +1217,9 @@ static struct request *blk_mq_map_request(struct request_queue *q,
        blk_mq_set_alloc_data(&alloc_data, q, 0, ctx, hctx);
        rq = __blk_mq_alloc_request(&alloc_data, op, op_flags);
 
-       hctx->queued++;
-       data->hctx = hctx;
-       data->ctx = ctx;
+       data->hctx = alloc_data.hctx;
+       data->ctx = alloc_data.ctx;
+       data->hctx->queued++;
        return rq;
 }
 
index 99cc64ac70efc2ca50f8832be098acadc3b57f76..bd6a029094e6b69455058eec51da6ce86fb8d036 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
 
 $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
 $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
+$(obj)/rsa_helper.o: $(obj)/rsapubkey-asn1.h $(obj)/rsaprivkey-asn1.h
 clean-files += rsapubkey-asn1.c rsapubkey-asn1.h
 clean-files += rsaprivkey-asn1.c rsaprivkey-asn1.h
 
index 80a0f1a7855181930afa0a545f5bf79584141e5c..e9c0993b131dc34d435d29358a037f56ca62e2b8 100644 (file)
@@ -81,7 +81,11 @@ static inline bool aead_sufficient_data(struct aead_ctx *ctx)
 {
        unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
 
-       return ctx->used >= ctx->aead_assoclen + as;
+       /*
+        * The minimum amount of memory needed for an AEAD cipher is
+        * the AAD and in case of decryption the tag.
+        */
+       return ctx->used >= ctx->aead_assoclen + (ctx->enc ? 0 : as);
 }
 
 static void aead_reset_ctx(struct aead_ctx *ctx)
@@ -416,7 +420,7 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
        unsigned int i, reqlen = GET_REQ_SIZE(tfm);
        int err = -ENOMEM;
        unsigned long used;
-       size_t outlen;
+       size_t outlen = 0;
        size_t usedpages = 0;
 
        lock_sock(sk);
@@ -426,12 +430,15 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
                        goto unlock;
        }
 
-       used = ctx->used;
-       outlen = used;
-
        if (!aead_sufficient_data(ctx))
                goto unlock;
 
+       used = ctx->used;
+       if (ctx->enc)
+               outlen = used + as;
+       else
+               outlen = used - as;
+
        req = sock_kmalloc(sk, reqlen, GFP_KERNEL);
        if (unlikely(!req))
                goto unlock;
@@ -445,7 +452,7 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
        aead_request_set_ad(req, ctx->aead_assoclen);
        aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
                                  aead_async_cb, sk);
-       used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
+       used -= ctx->aead_assoclen;
 
        /* take over all tx sgls from ctx */
        areq->tsgl = sock_kmalloc(sk, sizeof(*areq->tsgl) * sgl->cur,
@@ -461,7 +468,7 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
        areq->tsgls = sgl->cur;
 
        /* create rx sgls */
-       while (iov_iter_count(&msg->msg_iter)) {
+       while (outlen > usedpages && iov_iter_count(&msg->msg_iter)) {
                size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
                                      (outlen - usedpages));
 
@@ -491,16 +498,14 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
 
                last_rsgl = rsgl;
 
-               /* we do not need more iovecs as we have sufficient memory */
-               if (outlen <= usedpages)
-                       break;
-
                iov_iter_advance(&msg->msg_iter, err);
        }
-       err = -EINVAL;
+
        /* ensure output buffer is sufficiently large */
-       if (usedpages < outlen)
-               goto free;
+       if (usedpages < outlen) {
+               err = -EINVAL;
+               goto unlock;
+       }
 
        aead_request_set_crypt(req, areq->tsgl, areq->first_rsgl.sgl.sg, used,
                               areq->iv);
@@ -571,6 +576,7 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
                        goto unlock;
        }
 
+       /* data length provided by caller via sendmsg/sendpage */
        used = ctx->used;
 
        /*
@@ -585,16 +591,27 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
        if (!aead_sufficient_data(ctx))
                goto unlock;
 
-       outlen = used;
+       /*
+        * Calculate the minimum output buffer size holding the result of the
+        * cipher operation. When encrypting data, the receiving buffer is
+        * larger by the tag length compared to the input buffer as the
+        * encryption operation generates the tag. For decryption, the input
+        * buffer provides the tag which is consumed resulting in only the
+        * plaintext without a buffer for the tag returned to the caller.
+        */
+       if (ctx->enc)
+               outlen = used + as;
+       else
+               outlen = used - as;
 
        /*
         * The cipher operation input data is reduced by the associated data
         * length as this data is processed separately later on.
         */
-       used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
+       used -= ctx->aead_assoclen;
 
        /* convert iovecs of output buffers into scatterlists */
-       while (iov_iter_count(&msg->msg_iter)) {
+       while (outlen > usedpages && iov_iter_count(&msg->msg_iter)) {
                size_t seglen = min_t(size_t, iov_iter_count(&msg->msg_iter),
                                      (outlen - usedpages));
 
@@ -621,16 +638,14 @@ static int aead_recvmsg_sync(struct socket *sock, struct msghdr *msg, int flags)
 
                last_rsgl = rsgl;
 
-               /* we do not need more iovecs as we have sufficient memory */
-               if (outlen <= usedpages)
-                       break;
                iov_iter_advance(&msg->msg_iter, err);
        }
 
-       err = -EINVAL;
        /* ensure output buffer is sufficiently large */
-       if (usedpages < outlen)
+       if (usedpages < outlen) {
+               err = -EINVAL;
                goto unlock;
+       }
 
        sg_mark_end(sgl->sg + sgl->cur - 1);
        aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->first_rsgl.sgl.sg,
index 2d8466f9e49b8632527ed1e2f35617ff02f5fac1..d19b09cdf284d93dc63820a7cfc648217b220a7d 100644 (file)
@@ -214,23 +214,26 @@ static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
        ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
 
-       if (ctx->more) {
+       if (!result && !ctx->more) {
+               err = af_alg_wait_for_completion(
+                               crypto_ahash_init(&ctx->req),
+                               &ctx->completion);
+               if (err)
+                       goto unlock;
+       }
+
+       if (!result || ctx->more) {
                ctx->more = 0;
                err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req),
                                                 &ctx->completion);
                if (err)
                        goto unlock;
-       } else if (!result) {
-               err = af_alg_wait_for_completion(
-                               crypto_ahash_digest(&ctx->req),
-                               &ctx->completion);
        }
 
        err = memcpy_to_msg(msg, ctx->result, len);
 
-       hash_free_result(sk, ctx);
-
 unlock:
+       hash_free_result(sk, ctx);
        release_sock(sk);
 
        return err ?: len;
index 865f46ea724f285046542fab1639a4377d2a2aa1..c80765b211cf0fae7a91c35494dc9ed45247eafe 100644 (file)
@@ -133,7 +133,6 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
        return cert;
 
 error_decode:
-       kfree(cert->pub->key);
        kfree(ctx);
 error_no_ctx:
        x509_free_certificate(cert);
index fb33f7d3b052f5bb016342c1da2ef61b9f74ad8e..053035b5c8f85686446df108ccbf3675a19cd056 100644 (file)
@@ -262,6 +262,7 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                              u8 *inbuf, u32 inbuflen,
                              u8 *outbuf, u32 outlen);
 #define DRBG_CTR_NULL_LEN 128
+#define DRBG_OUTSCRATCHLEN DRBG_CTR_NULL_LEN
 
 /* BCC function for CTR DRBG as defined in 10.4.3 */
 static int drbg_ctr_bcc(struct drbg_state *drbg,
@@ -1644,6 +1645,9 @@ static int drbg_fini_sym_kernel(struct drbg_state *drbg)
        kfree(drbg->ctr_null_value_buf);
        drbg->ctr_null_value = NULL;
 
+       kfree(drbg->outscratchpadbuf);
+       drbg->outscratchpadbuf = NULL;
+
        return 0;
 }
 
@@ -1708,6 +1712,15 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg)
        drbg->ctr_null_value = (u8 *)PTR_ALIGN(drbg->ctr_null_value_buf,
                                               alignmask + 1);
 
+       drbg->outscratchpadbuf = kmalloc(DRBG_OUTSCRATCHLEN + alignmask,
+                                        GFP_KERNEL);
+       if (!drbg->outscratchpadbuf) {
+               drbg_fini_sym_kernel(drbg);
+               return -ENOMEM;
+       }
+       drbg->outscratchpad = (u8 *)PTR_ALIGN(drbg->outscratchpadbuf,
+                                             alignmask + 1);
+
        return alignmask;
 }
 
@@ -1737,15 +1750,16 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                              u8 *outbuf, u32 outlen)
 {
        struct scatterlist sg_in;
+       int ret;
 
        sg_init_one(&sg_in, inbuf, inlen);
 
        while (outlen) {
-               u32 cryptlen = min_t(u32, inlen, outlen);
+               u32 cryptlen = min3(inlen, outlen, (u32)DRBG_OUTSCRATCHLEN);
                struct scatterlist sg_out;
-               int ret;
 
-               sg_init_one(&sg_out, outbuf, cryptlen);
+               /* Output buffer may not be valid for SGL, use scratchpad */
+               sg_init_one(&sg_out, drbg->outscratchpad, cryptlen);
                skcipher_request_set_crypt(drbg->ctr_req, &sg_in, &sg_out,
                                           cryptlen, drbg->V);
                ret = crypto_skcipher_encrypt(drbg->ctr_req);
@@ -1761,14 +1775,19 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
                                break;
                        }
                default:
-                       return ret;
+                       goto out;
                }
                init_completion(&drbg->ctr_completion);
 
+               memcpy(outbuf, drbg->outscratchpad, cryptlen);
+
                outlen -= cryptlen;
        }
+       ret = 0;
 
-       return 0;
+out:
+       memzero_explicit(drbg->outscratchpad, DRBG_OUTSCRATCHLEN);
+       return ret;
 }
 #endif /* CONFIG_CRYPTO_DRBG_CTR */
 
index 94ee44acd4656811c081549b849c295ef160bd12..c207458d62993350d9a0cfca5e1deca573b09c8c 100644 (file)
@@ -254,18 +254,22 @@ out_free_inst:
        goto out;
 }
 
-static inline void mcryptd_check_internal(struct rtattr **tb, u32 *type,
+static inline bool mcryptd_check_internal(struct rtattr **tb, u32 *type,
                                          u32 *mask)
 {
        struct crypto_attr_type *algt;
 
        algt = crypto_get_attr_type(tb);
        if (IS_ERR(algt))
-               return;
-       if ((algt->type & CRYPTO_ALG_INTERNAL))
-               *type |= CRYPTO_ALG_INTERNAL;
-       if ((algt->mask & CRYPTO_ALG_INTERNAL))
-               *mask |= CRYPTO_ALG_INTERNAL;
+               return false;
+
+       *type |= algt->type & CRYPTO_ALG_INTERNAL;
+       *mask |= algt->mask & CRYPTO_ALG_INTERNAL;
+
+       if (*type & *mask & CRYPTO_ALG_INTERNAL)
+               return true;
+       else
+               return false;
 }
 
 static int mcryptd_hash_init_tfm(struct crypto_tfm *tfm)
@@ -492,7 +496,8 @@ static int mcryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
        u32 mask = 0;
        int err;
 
-       mcryptd_check_internal(tb, &type, &mask);
+       if (!mcryptd_check_internal(tb, &type, &mask))
+               return -EINVAL;
 
        halg = ahash_attr_alg(tb[1], type, mask);
        if (IS_ERR(halg))
index 52ce17a3dd63079c3f5bb6eacde40ec1a61aa2ab..c16c94f88733e738f4ee1dff7a1334f9c2e39eb4 100644 (file)
@@ -68,10 +68,6 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
 
        sg = scatterwalk_ffwd(tmp, sg, start);
 
-       if (sg_page(sg) == virt_to_page(buf) &&
-           sg->offset == offset_in_page(buf))
-               return;
-
        scatterwalk_start(&walk, sg);
        scatterwalk_copychunks(buf, &walk, nbytes, out);
        scatterwalk_done(&walk, out, 0);
index f0afdfb3c7df5c79a2d7cc21ef0bf10e0b30cbb2..194d20bee7dce40070964fa2343bc19ea946d627 100644 (file)
@@ -21,7 +21,7 @@ obj-y                         += video/
 obj-y                          += idle/
 
 # IPMI must come before ACPI in order to provide IPMI opregion support
-obj-$(CONFIG_IPMI_HANDLER)     += char/ipmi/
+obj-y                          += char/ipmi/
 
 obj-$(CONFIG_ACPI)             += acpi/
 obj-$(CONFIG_SFI)              += sfi/
index d58fbf7f04e6c7f4d901f648d9f26a0708cc6f15..7dd70927991e7e9e0de14a3af89db442eca8d175 100644 (file)
@@ -122,7 +122,7 @@ static int acpi_apd_create_device(struct acpi_device *adev,
        int ret;
 
        if (!dev_desc) {
-               pdev = acpi_create_platform_device(adev);
+               pdev = acpi_create_platform_device(adev, NULL);
                return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
        }
 
@@ -139,14 +139,8 @@ static int acpi_apd_create_device(struct acpi_device *adev,
                        goto err_out;
        }
 
-       if (dev_desc->properties) {
-               ret = device_add_properties(&adev->dev, dev_desc->properties);
-               if (ret)
-                       goto err_out;
-       }
-
        adev->driver_data = pdata;
-       pdev = acpi_create_platform_device(adev);
+       pdev = acpi_create_platform_device(adev, dev_desc->properties);
        if (!IS_ERR_OR_NULL(pdev))
                return 1;
 
index 5520102881357e005361ffd879dc7a245d2fd253..373657f7e35a9cac3a2a951cd030c00ef6fbd06d 100644 (file)
@@ -395,7 +395,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
 
        dev_desc = (const struct lpss_device_desc *)id->driver_data;
        if (!dev_desc) {
-               pdev = acpi_create_platform_device(adev);
+               pdev = acpi_create_platform_device(adev, NULL);
                return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
        }
        pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
@@ -451,14 +451,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
                goto err_out;
        }
 
-       if (dev_desc->properties) {
-               ret = device_add_properties(&adev->dev, dev_desc->properties);
-               if (ret)
-                       goto err_out;
-       }
-
        adev->driver_data = pdata;
-       pdev = acpi_create_platform_device(adev);
+       pdev = acpi_create_platform_device(adev, dev_desc->properties);
        if (!IS_ERR_OR_NULL(pdev)) {
                return 1;
        }
index b200ae1f3c6fb0fbef0a38135fd0b27e6da45041..b4c1a6a51da482a953051959279fc9d39cd29d49 100644 (file)
@@ -50,6 +50,7 @@ static void acpi_platform_fill_resource(struct acpi_device *adev,
 /**
  * acpi_create_platform_device - Create platform device for ACPI device node
  * @adev: ACPI device node to create a platform device for.
+ * @properties: Optional collection of build-in properties.
  *
  * Check if the given @adev can be represented as a platform device and, if
  * that's the case, create and register a platform device, populate its common
@@ -57,7 +58,8 @@ static void acpi_platform_fill_resource(struct acpi_device *adev,
  *
  * Name of the platform device will be the same as @adev's.
  */
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
+struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
+                                       struct property_entry *properties)
 {
        struct platform_device *pdev = NULL;
        struct platform_device_info pdevinfo;
@@ -106,6 +108,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
        pdevinfo.res = resources;
        pdevinfo.num_res = count;
        pdevinfo.fwnode = acpi_fwnode_handle(adev);
+       pdevinfo.properties = properties;
 
        if (acpi_dma_supported(adev))
                pdevinfo.dma_mask = DMA_BIT_MASK(32);
index f1e6dcc7a8271c6527e954299774841e5f4eaf78..54d48b90de2cd025710a71c03bcc88ea1ca75f32 100644 (file)
@@ -46,6 +46,7 @@
 #include "acdispat.h"
 #include "acnamesp.h"
 #include "actables.h"
+#include "acinterp.h"
 
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dsinit")
@@ -214,23 +215,17 @@ acpi_ds_initialize_objects(u32 table_index,
 
        /* Walk entire namespace from the supplied root */
 
-       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
        /*
         * We don't use acpi_walk_namespace since we do not want to acquire
         * the namespace reader lock.
         */
        status =
            acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
-                                  ACPI_NS_WALK_UNLOCK, acpi_ds_init_one_object,
-                                  NULL, &info, NULL);
+                                  0, acpi_ds_init_one_object, NULL, &info,
+                                  NULL);
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
        }
-       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 
        status = acpi_get_table_by_index(table_index, &table);
        if (ACPI_FAILURE(status)) {
index 32e9ddc0cf2bbbf4a73afc640956fcc92715bbcd..2b3210f42a46966f608c7729f02aef6b3aadffde 100644 (file)
@@ -99,14 +99,11 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
                          "Method auto-serialization parse [%4.4s] %p\n",
                          acpi_ut_get_node_name(node), node));
 
-       acpi_ex_enter_interpreter();
-
        /* Create/Init a root op for the method parse tree */
 
        op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start);
        if (!op) {
-               status = AE_NO_MEMORY;
-               goto unlock;
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
        acpi_ps_set_name(op, node->name.integer);
@@ -118,8 +115,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
            acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
        if (!walk_state) {
                acpi_ps_free_op(op);
-               status = AE_NO_MEMORY;
-               goto unlock;
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
        status = acpi_ds_init_aml_walk(walk_state, op, node,
@@ -138,8 +134,6 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
        status = acpi_ps_parse_aml(walk_state);
 
        acpi_ps_delete_parse_tree(op);
-unlock:
-       acpi_ex_exit_interpreter();
        return_ACPI_STATUS(status);
 }
 
@@ -730,26 +724,6 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
 
                acpi_ds_method_data_delete_all(walk_state);
 
-               /*
-                * If method is serialized, release the mutex and restore the
-                * current sync level for this thread
-                */
-               if (method_desc->method.mutex) {
-
-                       /* Acquisition Depth handles recursive calls */
-
-                       method_desc->method.mutex->mutex.acquisition_depth--;
-                       if (!method_desc->method.mutex->mutex.acquisition_depth) {
-                               walk_state->thread->current_sync_level =
-                                   method_desc->method.mutex->mutex.
-                                   original_sync_level;
-
-                               acpi_os_release_mutex(method_desc->method.
-                                                     mutex->mutex.os_mutex);
-                               method_desc->method.mutex->mutex.thread_id = 0;
-                       }
-               }
-
                /*
                 * Delete any namespace objects created anywhere within the
                 * namespace by the execution of this method. Unless:
@@ -786,6 +760,26 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
                                    ~ACPI_METHOD_MODIFIED_NAMESPACE;
                        }
                }
+
+               /*
+                * If method is serialized, release the mutex and restore the
+                * current sync level for this thread
+                */
+               if (method_desc->method.mutex) {
+
+                       /* Acquisition Depth handles recursive calls */
+
+                       method_desc->method.mutex->mutex.acquisition_depth--;
+                       if (!method_desc->method.mutex->mutex.acquisition_depth) {
+                               walk_state->thread->current_sync_level =
+                                   method_desc->method.mutex->mutex.
+                                   original_sync_level;
+
+                               acpi_os_release_mutex(method_desc->method.
+                                                     mutex->mutex.os_mutex);
+                               method_desc->method.mutex->mutex.thread_id = 0;
+                       }
+               }
        }
 
        /* Decrement the thread count on the method */
index 028b22a3154ebb888245d030bd38db6ce04cb3ab..e36218206bb013d030fc3d75487834403ecf5458 100644 (file)
@@ -607,11 +607,9 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
                                }
                        }
 
-                       acpi_ex_exit_interpreter();
                        status =
                            acpi_ev_initialize_region
                            (acpi_ns_get_attached_object(node), FALSE);
-                       acpi_ex_enter_interpreter();
 
                        if (ACPI_FAILURE(status)) {
                                /*
index 3843f1fc5dbbd6166a2005302d8df22726fd0fa4..75ddd160a716faaa10c81ac92ddca37d1a73dcbf 100644 (file)
@@ -45,6 +45,7 @@
 #include "accommon.h"
 #include "acevents.h"
 #include "acnamesp.h"
+#include "acinterp.h"
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evrgnini")
@@ -597,9 +598,11 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
                                        }
                                }
 
+                               acpi_ex_exit_interpreter();
                                status =
                                    acpi_ev_execute_reg_method(region_obj,
                                                               ACPI_REG_CONNECT);
+                               acpi_ex_enter_interpreter();
 
                                if (acpi_ns_locked) {
                                        status =
index 334d3c5ba617dc23a46198bdd3ccaafe9b12223f..d1f20143bb113ffdc751514d793f929aab38bec1 100644 (file)
@@ -137,7 +137,9 @@ unlock:
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "**** Begin Table Object Initialization\n"));
 
+       acpi_ex_enter_interpreter();
        status = acpi_ds_initialize_objects(table_index, node);
+       acpi_ex_exit_interpreter();
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "**** Completed Table Object Initialization\n"));
index 046c4d0394eedd9a5c84cf813deb01506b52068b..5fb838e592dc430c49b657ce6fba3dce1572676f 100644 (file)
@@ -480,19 +480,17 @@ static void acpi_tb_convert_fadt(void)
        u32 i;
 
        /*
-        * For ACPI 1.0 FADTs (revision 1), ensure that reserved fields which
+        * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
         * should be zero are indeed zero. This will workaround BIOSs that
         * inadvertently place values in these fields.
         *
         * The ACPI 1.0 reserved fields that will be zeroed are the bytes located
         * at offset 45, 55, 95, and the word located at offset 109, 110.
         *
-        * Note: The FADT revision value is unreliable because of BIOS errors.
-        * The table length is instead used as the final word on the version.
-        *
-        * Note: FADT revision 3 is the ACPI 2.0 version of the FADT.
+        * Note: The FADT revision value is unreliable. Only the length can be
+        * trusted.
         */
-       if (acpi_gbl_FADT.header.length <= ACPI_FADT_V3_SIZE) {
+       if (acpi_gbl_FADT.header.length <= ACPI_FADT_V2_SIZE) {
                acpi_gbl_FADT.preferred_profile = 0;
                acpi_gbl_FADT.pstate_control = 0;
                acpi_gbl_FADT.cst_control = 0;
index f0a029e68d3e2989b7e3ad79a02d1d0c36e1b0f4..0d099a24f776ac9bd665f3aab8006793031aef48 100644 (file)
@@ -662,7 +662,7 @@ static int ghes_proc(struct ghes *ghes)
        ghes_do_proc(ghes, ghes->estatus);
 out:
        ghes_clear_estatus(ghes);
-       return 0;
+       return rc;
 }
 
 static void ghes_add_timer(struct ghes *ghes)
index 33505c651f62792e136cedc73a8b022c10f2ba21..86364097e236e5d2d7d99b4e4e94f67b7560ebfd 100644 (file)
@@ -34,11 +34,11 @@ static int int340x_thermal_handler_attach(struct acpi_device *adev,
                                        const struct acpi_device_id *id)
 {
        if (IS_ENABLED(CONFIG_INT340X_THERMAL))
-               acpi_create_platform_device(adev);
+               acpi_create_platform_device(adev, NULL);
        /* Intel SoC DTS thermal driver needs INT3401 to set IRQ descriptor */
        else if (IS_ENABLED(CONFIG_INTEL_SOC_DTS_THERMAL) &&
                 id->driver_data == INT3401_DEVICE)
-               acpi_create_platform_device(adev);
+               acpi_create_platform_device(adev, NULL);
        return 1;
 }
 
index 71a7d07c28c9447d8ed41bc18c7f3ec4dcc83607..312c4b4dc363fdbc4847d3db55c0cfbfbb80f5f4 100644 (file)
@@ -94,7 +94,7 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
        return to_acpi_device(acpi_desc->dev);
 }
 
-static int xlat_status(void *buf, unsigned int cmd, u32 status)
+static int xlat_bus_status(void *buf, unsigned int cmd, u32 status)
 {
        struct nd_cmd_clear_error *clear_err;
        struct nd_cmd_ars_status *ars_status;
@@ -113,7 +113,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
                flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
                if ((status >> 16 & flags) == 0)
                        return -ENOTTY;
-               break;
+               return 0;
        case ND_CMD_ARS_START:
                /* ARS is in progress */
                if ((status & 0xffff) == NFIT_ARS_START_BUSY)
@@ -122,7 +122,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
                /* Command failed */
                if (status & 0xffff)
                        return -EIO;
-               break;
+               return 0;
        case ND_CMD_ARS_STATUS:
                ars_status = buf;
                /* Command failed */
@@ -146,7 +146,8 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
                 * then just continue with the returned results.
                 */
                if (status == NFIT_ARS_STATUS_INTR) {
-                       if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
+                       if (ars_status->out_length >= 40 && (ars_status->flags
+                                               & NFIT_ARS_F_OVERFLOW))
                                return -ENOSPC;
                        return 0;
                }
@@ -154,7 +155,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
                /* Unknown status */
                if (status >> 16)
                        return -EIO;
-               break;
+               return 0;
        case ND_CMD_CLEAR_ERROR:
                clear_err = buf;
                if (status & 0xffff)
@@ -163,7 +164,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
                        return -EIO;
                if (clear_err->length > clear_err->cleared)
                        return clear_err->cleared;
-               break;
+               return 0;
        default:
                break;
        }
@@ -174,9 +175,18 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
        return 0;
 }
 
-static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
-               struct nvdimm *nvdimm, unsigned int cmd, void *buf,
-               unsigned int buf_len, int *cmd_rc)
+static int xlat_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd,
+               u32 status)
+{
+       if (!nvdimm)
+               return xlat_bus_status(buf, cmd, status);
+       if (status)
+               return -EIO;
+       return 0;
+}
+
+int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
+               unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc)
 {
        struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
        union acpi_object in_obj, in_buf, *out_obj;
@@ -298,7 +308,8 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
 
        for (i = 0, offset = 0; i < desc->out_num; i++) {
                u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf,
-                               (u32 *) out_obj->buffer.pointer);
+                               (u32 *) out_obj->buffer.pointer,
+                               out_obj->buffer.length - offset);
 
                if (offset + out_size > out_obj->buffer.length) {
                        dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
@@ -333,7 +344,8 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
                         */
                        rc = buf_len - offset - in_buf.buffer.length;
                        if (cmd_rc)
-                               *cmd_rc = xlat_status(buf, cmd, fw_status);
+                               *cmd_rc = xlat_status(nvdimm, buf, cmd,
+                                               fw_status);
                } else {
                        dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
                                        __func__, dimm_name, cmd_name, buf_len,
@@ -343,7 +355,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
        } else {
                rc = 0;
                if (cmd_rc)
-                       *cmd_rc = xlat_status(buf, cmd, fw_status);
+                       *cmd_rc = xlat_status(nvdimm, buf, cmd, fw_status);
        }
 
  out:
@@ -351,6 +363,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(acpi_nfit_ctl);
 
 static const char *spa_type_name(u16 type)
 {
@@ -2001,19 +2014,32 @@ static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
        return cmd_rc;
 }
 
-static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
+static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc,
                struct nd_cmd_ars_status *ars_status)
 {
+       struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
        int rc;
        u32 i;
 
+       /*
+        * First record starts at 44 byte offset from the start of the
+        * payload.
+        */
+       if (ars_status->out_length < 44)
+               return 0;
        for (i = 0; i < ars_status->num_records; i++) {
+               /* only process full records */
+               if (ars_status->out_length
+                               < 44 + sizeof(struct nd_ars_record) * (i + 1))
+                       break;
                rc = nvdimm_bus_add_poison(nvdimm_bus,
                                ars_status->records[i].err_address,
                                ars_status->records[i].length);
                if (rc)
                        return rc;
        }
+       if (i < ars_status->num_records)
+               dev_warn(acpi_desc->dev, "detected truncated ars results\n");
 
        return 0;
 }
@@ -2266,8 +2292,7 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
        if (rc < 0 && rc != -ENOSPC)
                return rc;
 
-       if (ars_status_process_records(acpi_desc->nvdimm_bus,
-                               acpi_desc->ars_status))
+       if (ars_status_process_records(acpi_desc, acpi_desc->ars_status))
                return -ENOMEM;
 
        return 0;
index 14296f5267c8c45a2826b9b82a40dbe8aedf1918..fc29c2e9832e5b1b355d15e8edb8bc0278e31fdb 100644 (file)
@@ -240,5 +240,7 @@ const u8 *to_nfit_uuid(enum nfit_uuids id);
 int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz);
 void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event);
 void __acpi_nvdimm_notify(struct device *dev, u32 event);
+int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
+               unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc);
 void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
 #endif /* __NFIT_H__ */
index c983bf733ad37d7b608c9410108dcef32cdbf02b..bc3d914dfc3e397880581b56b33188f575ea160d 100644 (file)
@@ -87,6 +87,7 @@ struct acpi_pci_link {
 
 static LIST_HEAD(acpi_link_list);
 static DEFINE_MUTEX(acpi_link_lock);
+static int sci_irq = -1, sci_penalty;
 
 /* --------------------------------------------------------------------------
                             PCI Link Device Management
@@ -496,25 +497,13 @@ static int acpi_irq_get_penalty(int irq)
 {
        int penalty = 0;
 
-       /*
-       * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict
-       * with PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be
-       * use for PCI IRQs.
-       */
-       if (irq == acpi_gbl_FADT.sci_interrupt) {
-               u32 type = irq_get_trigger_type(irq) & IRQ_TYPE_SENSE_MASK;
-
-               if (type != IRQ_TYPE_LEVEL_LOW)
-                       penalty += PIRQ_PENALTY_ISA_ALWAYS;
-               else
-                       penalty += PIRQ_PENALTY_PCI_USING;
-       }
+       if (irq == sci_irq)
+               penalty += sci_penalty;
 
        if (irq < ACPI_MAX_ISA_IRQS)
                return penalty + acpi_isa_irq_penalty[irq];
 
-       penalty += acpi_irq_pci_sharing_penalty(irq);
-       return penalty;
+       return penalty + acpi_irq_pci_sharing_penalty(irq);
 }
 
 int __init acpi_irq_penalty_init(void)
@@ -619,6 +608,10 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
                            acpi_device_bid(link->device));
                return -ENODEV;
        } else {
+               if (link->irq.active < ACPI_MAX_ISA_IRQS)
+                       acpi_isa_irq_penalty[link->irq.active] +=
+                               PIRQ_PENALTY_PCI_USING;
+
                printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
                       acpi_device_name(link->device),
                       acpi_device_bid(link->device), link->irq.active);
@@ -849,7 +842,7 @@ static int __init acpi_irq_penalty_update(char *str, int used)
                        continue;
 
                if (used)
-                       new_penalty = acpi_irq_get_penalty(irq) +
+                       new_penalty = acpi_isa_irq_penalty[irq] +
                                        PIRQ_PENALTY_ISA_USED;
                else
                        new_penalty = 0;
@@ -871,7 +864,7 @@ static int __init acpi_irq_penalty_update(char *str, int used)
 void acpi_penalize_isa_irq(int irq, int active)
 {
        if ((irq >= 0) && (irq < ARRAY_SIZE(acpi_isa_irq_penalty)))
-               acpi_isa_irq_penalty[irq] = acpi_irq_get_penalty(irq) +
+               acpi_isa_irq_penalty[irq] +=
                  (active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
 }
 
@@ -881,6 +874,17 @@ bool acpi_isa_irq_available(int irq)
                    acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
 }
 
+void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
+{
+       sci_irq = irq;
+
+       if (trigger == ACPI_MADT_TRIGGER_LEVEL &&
+           polarity == ACPI_MADT_POLARITY_ACTIVE_LOW)
+               sci_penalty = PIRQ_PENALTY_PCI_USING;
+       else
+               sci_penalty = PIRQ_PENALTY_ISA_ALWAYS;
+}
+
 /*
  * Over-ride default table to reserve additional IRQs for use by ISA
  * e.g. acpi_irq_isa=5
index 035ac646d8db55272bf2182f690e0452b8d7a485..3d1856f1f4d03eb8c47e5e4043684d7b5b76b046 100644 (file)
@@ -1734,7 +1734,7 @@ static void acpi_default_enumeration(struct acpi_device *device)
                               &is_spi_i2c_slave);
        acpi_dev_free_resource_list(&resource_list);
        if (!is_spi_i2c_slave) {
-               acpi_create_platform_device(device);
+               acpi_create_platform_device(device, NULL);
                acpi_device_set_enumerated(device);
        } else {
                blocking_notifier_call_chain(&acpi_reconfig_chain,
index deb0ff78eba8705b56292d1acf2e206541ee8bf8..54abb26b736639ca54aa7051ae742d6657a501bc 100644 (file)
@@ -47,32 +47,15 @@ static void acpi_sleep_tts_switch(u32 acpi_state)
        }
 }
 
-static void acpi_sleep_pts_switch(u32 acpi_state)
-{
-       acpi_status status;
-
-       status = acpi_execute_simple_method(NULL, "\\_PTS", acpi_state);
-       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-               /*
-                * OS can't evaluate the _PTS object correctly. Some warning
-                * message will be printed. But it won't break anything.
-                */
-               printk(KERN_NOTICE "Failure in evaluating _PTS object\n");
-       }
-}
-
-static int sleep_notify_reboot(struct notifier_block *this,
+static int tts_notify_reboot(struct notifier_block *this,
                        unsigned long code, void *x)
 {
        acpi_sleep_tts_switch(ACPI_STATE_S5);
-
-       acpi_sleep_pts_switch(ACPI_STATE_S5);
-
        return NOTIFY_DONE;
 }
 
-static struct notifier_block sleep_notifier = {
-       .notifier_call  = sleep_notify_reboot,
+static struct notifier_block tts_notifier = {
+       .notifier_call  = tts_notify_reboot,
        .next           = NULL,
        .priority       = 0,
 };
@@ -916,9 +899,9 @@ int __init acpi_sleep_init(void)
        pr_info(PREFIX "(supports%s)\n", supported);
 
        /*
-        * Register the sleep_notifier to reboot notifier list so that the _TTS
-        * and _PTS object can also be evaluated when the system enters S5.
+        * Register the tts_notifier to reboot notifier list so that the _TTS
+        * object can also be evaluated when the system enters S5.
         */
-       register_reboot_notifier(&sleep_notifier);
+       register_reboot_notifier(&tts_notifier);
        return 0;
 }
index 562af94bec357f09ab1a33394a2ec742f9f88977..3c71b982bf2a35ae1a406e35fac2683577edb2b8 100644 (file)
@@ -1002,7 +1002,7 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal)
 
 
 static struct binder_ref *binder_get_ref(struct binder_proc *proc,
-                                        uint32_t desc)
+                                        u32 desc, bool need_strong_ref)
 {
        struct rb_node *n = proc->refs_by_desc.rb_node;
        struct binder_ref *ref;
@@ -1010,12 +1010,16 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc,
        while (n) {
                ref = rb_entry(n, struct binder_ref, rb_node_desc);
 
-               if (desc < ref->desc)
+               if (desc < ref->desc) {
                        n = n->rb_left;
-               else if (desc > ref->desc)
+               } else if (desc > ref->desc) {
                        n = n->rb_right;
-               else
+               } else if (need_strong_ref && !ref->strong) {
+                       binder_user_error("tried to use weak ref as strong ref\n");
+                       return NULL;
+               } else {
                        return ref;
+               }
        }
        return NULL;
 }
@@ -1285,7 +1289,10 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+                       struct binder_ref *ref;
+
+                       ref = binder_get_ref(proc, fp->handle,
+                                            fp->type == BINDER_TYPE_HANDLE);
 
                        if (ref == NULL) {
                                pr_err("transaction release %d bad handle %d\n",
@@ -1380,7 +1387,7 @@ static void binder_transaction(struct binder_proc *proc,
                if (tr->target.handle) {
                        struct binder_ref *ref;
 
-                       ref = binder_get_ref(proc, tr->target.handle);
+                       ref = binder_get_ref(proc, tr->target.handle, true);
                        if (ref == NULL) {
                                binder_user_error("%d:%d got transaction to invalid handle\n",
                                        proc->pid, thread->pid);
@@ -1577,7 +1584,9 @@ static void binder_transaction(struct binder_proc *proc,
                                fp->type = BINDER_TYPE_HANDLE;
                        else
                                fp->type = BINDER_TYPE_WEAK_HANDLE;
+                       fp->binder = 0;
                        fp->handle = ref->desc;
+                       fp->cookie = 0;
                        binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                                       &thread->todo);
 
@@ -1589,7 +1598,10 @@ static void binder_transaction(struct binder_proc *proc,
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+                       struct binder_ref *ref;
+
+                       ref = binder_get_ref(proc, fp->handle,
+                                            fp->type == BINDER_TYPE_HANDLE);
 
                        if (ref == NULL) {
                                binder_user_error("%d:%d got transaction with invalid handle, %d\n",
@@ -1624,7 +1636,9 @@ static void binder_transaction(struct binder_proc *proc,
                                        return_error = BR_FAILED_REPLY;
                                        goto err_binder_get_ref_for_node_failed;
                                }
+                               fp->binder = 0;
                                fp->handle = new_ref->desc;
+                               fp->cookie = 0;
                                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                                trace_binder_transaction_ref_to_ref(t, ref,
                                                                    new_ref);
@@ -1678,6 +1692,7 @@ static void binder_transaction(struct binder_proc *proc,
                        binder_debug(BINDER_DEBUG_TRANSACTION,
                                     "        fd %d -> %d\n", fp->handle, target_fd);
                        /* TODO: fput? */
+                       fp->binder = 0;
                        fp->handle = target_fd;
                } break;
 
@@ -1800,7 +1815,9 @@ static int binder_thread_write(struct binder_proc *proc,
                                                ref->desc);
                                }
                        } else
-                               ref = binder_get_ref(proc, target);
+                               ref = binder_get_ref(proc, target,
+                                                    cmd == BC_ACQUIRE ||
+                                                    cmd == BC_RELEASE);
                        if (ref == NULL) {
                                binder_user_error("%d:%d refcount change on invalid ref %d\n",
                                        proc->pid, thread->pid, target);
@@ -1996,7 +2013,7 @@ static int binder_thread_write(struct binder_proc *proc,
                        if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                                return -EFAULT;
                        ptr += sizeof(binder_uintptr_t);
-                       ref = binder_get_ref(proc, target);
+                       ref = binder_get_ref(proc, target, false);
                        if (ref == NULL) {
                                binder_user_error("%d:%d %s invalid ref %d\n",
                                        proc->pid, thread->pid,
index ba5f11cebee2a1ce6528116cdc9af25b7a25af44..74f4c662f776ecf546d4c61a7de4190a61870b5c 100644 (file)
@@ -1418,30 +1418,26 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
         * Message mode could be enforced. In this case assume that advantage
         * of multipe MSIs is negated and use single MSI mode instead.
         */
-       nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX,
-                       PCI_IRQ_MSIX | PCI_IRQ_MSI);
-       if (nvec > 0) {
-               if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) {
-                       hpriv->get_irq_vector = ahci_get_irq_vector;
-                       hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
-                       return nvec;
-               }
+       if (n_ports > 1) {
+               nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX,
+                               PCI_IRQ_MSIX | PCI_IRQ_MSI);
+               if (nvec > 0) {
+                       if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) {
+                               hpriv->get_irq_vector = ahci_get_irq_vector;
+                               hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+                               return nvec;
+                       }
 
-               /*
-                * Fallback to single MSI mode if the controller enforced MRSM
-                * mode.
-                */
-               printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n");
-               pci_free_irq_vectors(pdev);
+                       /*
+                        * Fallback to single MSI mode if the controller
+                        * enforced MRSM mode.
+                        */
+                       printk(KERN_INFO
+                               "ahci: MRSM is on, fallback to single MSI\n");
+                       pci_free_irq_vectors(pdev);
+               }
        }
 
-       /*
-        * -ENOSPC indicated we don't have enough vectors.  Don't bother trying
-        * a single vectors for any other error:
-        */
-       if (nvec < 0 && nvec != -ENOSPC)
-               return nvec;
-
        /*
         * If the host is not capable of supporting per-port vectors, fall
         * back to single MSI before finally attempting single MSI-X.
@@ -1617,7 +1613,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                /* legacy intx interrupts */
                pci_intx(pdev, 1);
        }
-       hpriv->irq = pdev->irq;
+       hpriv->irq = pci_irq_vector(pdev, 0);
 
        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
                host->flags |= ATA_HOST_PARALLEL_SCAN;
index 9cceb4a875a58caa19fdd809ad82181f22676fc2..8e575fbdf31d6b5737046111d55600a8638e595b 100644 (file)
@@ -1088,7 +1088,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
                desc[1] = tf->command; /* status */
                desc[2] = tf->device;
                desc[3] = tf->nsect;
-               desc[0] = 0;
+               desc[7] = 0;
                if (tf->flags & ATA_TFLAG_LBA48)  {
                        desc[8] |= 0x80;
                        if (tf->hob_nsect)
@@ -1159,6 +1159,7 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
 {
        sdev->use_10_for_rw = 1;
        sdev->use_10_for_ms = 1;
+       sdev->no_write_same = 1;
 
        /* Schedule policy is determined by ->qc_defer() callback and
         * it needs to see every deferred qc.  Set dev_blocked to 1 to
index efc48bf89d5182a6b4b4150b522fabc2cc1844ee..823e938c9a7877a1cadefde9127d447832630061 100644 (file)
@@ -4090,7 +4090,20 @@ static int mv_platform_probe(struct platform_device *pdev)
 
        /* allocate host */
        if (pdev->dev.of_node) {
-               of_property_read_u32(pdev->dev.of_node, "nr-ports", &n_ports);
+               rc = of_property_read_u32(pdev->dev.of_node, "nr-ports",
+                                          &n_ports);
+               if (rc) {
+                       dev_err(&pdev->dev,
+                               "error parsing nr-ports property: %d\n", rc);
+                       return rc;
+               }
+
+               if (n_ports <= 0) {
+                       dev_err(&pdev->dev, "nr-ports must be positive: %d\n",
+                               n_ports);
+                       return -EINVAL;
+               }
+
                irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
        } else {
                mv_platform_data = dev_get_platdata(&pdev->dev);
index f2aaf9e32a36aa71ece80e6edc39b01b411c74d3..40c2d561417bdecd6bd386f3c92214a51a6faece 100644 (file)
@@ -1727,7 +1727,7 @@ static int eni_do_init(struct atm_dev *dev)
                printk("\n");
                printk(KERN_ERR DEV_LABEL "(itf %d): can't set up page "
                    "mapping\n",dev->number);
-               return error;
+               return -ENOMEM;
        }
        eni_dev->ioaddr = base;
        eni_dev->base_diff = real_base - (unsigned long) base;
index ce43ae3e87b3513245cf5b322d5a4b4984ec9dfa..445505d9ea07187902ed95c6ae121591b23cef5c 100644 (file)
@@ -2143,6 +2143,7 @@ static int lanai_dev_open(struct atm_dev *atmdev)
        lanai->base = (bus_addr_t) ioremap(raw_base, LANAI_MAPPING_SIZE);
        if (lanai->base == NULL) {
                printk(KERN_ERR DEV_LABEL ": couldn't remap I/O space\n");
+               result = -ENOMEM;
                goto error_pci;
        }
        /* 3.3: Reset lanai and PHY */
index fdf44cac08e6d0026dab6095f46b55924cd89b1d..d02e7c0f5bfdff1c6c56372113e230e55be54f5f 100644 (file)
@@ -213,14 +213,16 @@ config DEBUG_DEVRES
          If you are unsure about this, Say N here.
 
 config DEBUG_TEST_DRIVER_REMOVE
-       bool "Test driver remove calls during probe"
+       bool "Test driver remove calls during probe (UNSTABLE)"
        depends on DEBUG_KERNEL
        help
          Say Y here if you want the Driver core to test driver remove functions
          by calling probe, remove, probe. This tests the remove path without
          having to unbind the driver or unload the driver module.
 
-         If you are unsure about this, say N here.
+         This option is expected to find errors and may render your system
+         unusable. You should say N here unless you are explicitly looking to
+         test this functionality.
 
 config SYS_HYPERVISOR
        bool
index d22a7260f42b26f498037f35c943b547300181dc..d76cd97a98b6badff85740180dfec97c8966754a 100644 (file)
@@ -324,7 +324,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
 {
        int ret = -EPROBE_DEFER;
        int local_trigger_count = atomic_read(&deferred_trigger_count);
-       bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE);
+       bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
+                          !drv->suppress_bind_attrs;
 
        if (defer_all_probes) {
                /*
@@ -383,7 +384,7 @@ re_probe:
        if (test_remove) {
                test_remove = false;
 
-               if (dev->bus && dev->bus->remove)
+               if (dev->bus->remove)
                        dev->bus->remove(dev);
                else if (drv->remove)
                        drv->remove(dev);
index e44944f4be77d0a573e4e46850849b52ba09a349..2932a5bd892f7e2b400d5b806c7df36b3cdc30a8 100644 (file)
@@ -1027,6 +1027,8 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
        TRACE_DEVICE(dev);
        TRACE_SUSPEND(0);
 
+       dpm_wait_for_children(dev, async);
+
        if (async_error)
                goto Complete;
 
@@ -1038,8 +1040,6 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
        if (dev->power.syscore || dev->power.direct_complete)
                goto Complete;
 
-       dpm_wait_for_children(dev, async);
-
        if (dev->pm_domain) {
                info = "noirq power domain ";
                callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -1174,6 +1174,8 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
 
        __pm_runtime_disable(dev, false);
 
+       dpm_wait_for_children(dev, async);
+
        if (async_error)
                goto Complete;
 
@@ -1185,8 +1187,6 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
        if (dev->power.syscore || dev->power.direct_complete)
                goto Complete;
 
-       dpm_wait_for_children(dev, async);
-
        if (dev->pm_domain) {
                info = "late power domain ";
                callback = pm_late_early_op(&dev->pm_domain->ops, state);
index 811e11c82f32907a98a02a442ecb76cb1da471fb..0809cda93cc031360257c7f0802964e15f0f0d51 100644 (file)
@@ -2954,7 +2954,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device,
        case DAC960_PD_Controller:
          if (!request_region(Controller->IO_Address, 0x80,
                              Controller->FullModelName)) {
-               DAC960_Error("IO port 0x%d busy for Controller at\n",
+               DAC960_Error("IO port 0x%lx busy for Controller at\n",
                             Controller, Controller->IO_Address);
                goto Failure;
          }
@@ -2990,7 +2990,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device,
        case DAC960_P_Controller:
          if (!request_region(Controller->IO_Address, 0x80,
                              Controller->FullModelName)){
-               DAC960_Error("IO port 0x%d busy for Controller at\n",
+               DAC960_Error("IO port 0x%lx busy for Controller at\n",
                             Controller, Controller->IO_Address);
                goto Failure;
          }
index ab19adb07a126ae0cae4f0d37170a2929367b115..3c606c09fd5acbd2897c680c3249929f30b6a9a8 100644 (file)
@@ -853,45 +853,6 @@ rqbiocnt(struct request *r)
        return n;
 }
 
-/* This can be removed if we are certain that no users of the block
- * layer will ever use zero-count pages in bios.  Otherwise we have to
- * protect against the put_page sometimes done by the network layer.
- *
- * See http://oss.sgi.com/archives/xfs/2007-01/msg00594.html for
- * discussion.
- *
- * We cannot use get_page in the workaround, because it insists on a
- * positive page count as a precondition.  So we use _refcount directly.
- */
-static void
-bio_pageinc(struct bio *bio)
-{
-       struct bio_vec bv;
-       struct page *page;
-       struct bvec_iter iter;
-
-       bio_for_each_segment(bv, bio, iter) {
-               /* Non-zero page count for non-head members of
-                * compound pages is no longer allowed by the kernel.
-                */
-               page = compound_head(bv.bv_page);
-               page_ref_inc(page);
-       }
-}
-
-static void
-bio_pagedec(struct bio *bio)
-{
-       struct page *page;
-       struct bio_vec bv;
-       struct bvec_iter iter;
-
-       bio_for_each_segment(bv, bio, iter) {
-               page = compound_head(bv.bv_page);
-               page_ref_dec(page);
-       }
-}
-
 static void
 bufinit(struct buf *buf, struct request *rq, struct bio *bio)
 {
@@ -899,7 +860,6 @@ bufinit(struct buf *buf, struct request *rq, struct bio *bio)
        buf->rq = rq;
        buf->bio = bio;
        buf->iter = bio->bi_iter;
-       bio_pageinc(bio);
 }
 
 static struct buf *
@@ -1127,7 +1087,6 @@ aoe_end_buf(struct aoedev *d, struct buf *buf)
        if (buf == d->ip.buf)
                d->ip.buf = NULL;
        rq = buf->rq;
-       bio_pagedec(buf->bio);
        mempool_free(buf, d->bufpool);
        n = (unsigned long) rq->special;
        rq->special = (void *) --n;
index 100be556e6137ce1e5731fd68eec5b317ed3bcc8..83482721bc012739cf25ee627fd2b85b2fd094ab 100644 (file)
@@ -1871,7 +1871,7 @@ int drbd_send(struct drbd_connection *connection, struct socket *sock,
                drbd_update_congested(connection);
        }
        do {
-               rv = kernel_sendmsg(sock, &msg, &iov, 1, size);
+               rv = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
                if (rv == -EAGAIN) {
                        if (we_should_drop_the_connection(connection, sock))
                                break;
index ba405b55329fb7d784213ea582eae429f05c2bc2..7a104875591400a896ab3025e5feb4e37ec3e86a 100644 (file)
@@ -164,7 +164,7 @@ static void sock_shutdown(struct nbd_device *nbd)
        spin_lock(&nbd->sock_lock);
 
        if (!nbd->sock) {
-               spin_unlock_irq(&nbd->sock_lock);
+               spin_unlock(&nbd->sock_lock);
                return;
        }
 
@@ -599,7 +599,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                        return -EINVAL;
 
                sreq = blk_mq_alloc_request(bdev_get_queue(bdev), WRITE, 0);
-               if (!sreq)
+               if (IS_ERR(sreq))
                        return -ENOMEM;
 
                mutex_unlock(&nbd->tx_lock);
index abb71628ab614628d62acd3d16a91ee9eae8c9b4..7b274ff4632c6944e32b95d605ee9aa9769f7082 100644 (file)
@@ -415,15 +415,15 @@ struct rbd_device {
 };
 
 /*
- * Flag bits for rbd_dev->flags.  If atomicity is required,
- * rbd_dev->lock is used to protect access.
- *
- * Currently, only the "removing" flag (which is coupled with the
- * "open_count" field) requires atomic access.
+ * Flag bits for rbd_dev->flags:
+ * - REMOVING (which is coupled with rbd_dev->open_count) is protected
+ *   by rbd_dev->lock
+ * - BLACKLISTED is protected by rbd_dev->lock_rwsem
  */
 enum rbd_dev_flags {
        RBD_DEV_FLAG_EXISTS,    /* mapped snapshot has not been deleted */
        RBD_DEV_FLAG_REMOVING,  /* this mapping is being removed */
+       RBD_DEV_FLAG_BLACKLISTED, /* our ceph_client is blacklisted */
 };
 
 static DEFINE_MUTEX(client_mutex);     /* Serialize client creation */
@@ -3926,6 +3926,7 @@ static void rbd_reregister_watch(struct work_struct *work)
        struct rbd_device *rbd_dev = container_of(to_delayed_work(work),
                                            struct rbd_device, watch_dwork);
        bool was_lock_owner = false;
+       bool need_to_wake = false;
        int ret;
 
        dout("%s rbd_dev %p\n", __func__, rbd_dev);
@@ -3935,19 +3936,27 @@ static void rbd_reregister_watch(struct work_struct *work)
                was_lock_owner = rbd_release_lock(rbd_dev);
 
        mutex_lock(&rbd_dev->watch_mutex);
-       if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR)
-               goto fail_unlock;
+       if (rbd_dev->watch_state != RBD_WATCH_STATE_ERROR) {
+               mutex_unlock(&rbd_dev->watch_mutex);
+               goto out;
+       }
 
        ret = __rbd_register_watch(rbd_dev);
        if (ret) {
                rbd_warn(rbd_dev, "failed to reregister watch: %d", ret);
-               if (ret != -EBLACKLISTED)
+               if (ret == -EBLACKLISTED || ret == -ENOENT) {
+                       set_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags);
+                       need_to_wake = true;
+               } else {
                        queue_delayed_work(rbd_dev->task_wq,
                                           &rbd_dev->watch_dwork,
                                           RBD_RETRY_DELAY);
-               goto fail_unlock;
+               }
+               mutex_unlock(&rbd_dev->watch_mutex);
+               goto out;
        }
 
+       need_to_wake = true;
        rbd_dev->watch_state = RBD_WATCH_STATE_REGISTERED;
        rbd_dev->watch_cookie = rbd_dev->watch_handle->linger_id;
        mutex_unlock(&rbd_dev->watch_mutex);
@@ -3963,13 +3972,10 @@ static void rbd_reregister_watch(struct work_struct *work)
                                 ret);
        }
 
+out:
        up_write(&rbd_dev->lock_rwsem);
-       wake_requests(rbd_dev, true);
-       return;
-
-fail_unlock:
-       mutex_unlock(&rbd_dev->watch_mutex);
-       up_write(&rbd_dev->lock_rwsem);
+       if (need_to_wake)
+               wake_requests(rbd_dev, true);
 }
 
 /*
@@ -4074,7 +4080,9 @@ static void rbd_wait_state_locked(struct rbd_device *rbd_dev)
                up_read(&rbd_dev->lock_rwsem);
                schedule();
                down_read(&rbd_dev->lock_rwsem);
-       } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED);
+       } while (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED &&
+                !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags));
+
        finish_wait(&rbd_dev->lock_waitq, &wait);
 }
 
@@ -4166,8 +4174,16 @@ static void rbd_queue_workfn(struct work_struct *work)
 
        if (must_be_locked) {
                down_read(&rbd_dev->lock_rwsem);
-               if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED)
+               if (rbd_dev->lock_state != RBD_LOCK_STATE_LOCKED &&
+                   !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags))
                        rbd_wait_state_locked(rbd_dev);
+
+               WARN_ON((rbd_dev->lock_state == RBD_LOCK_STATE_LOCKED) ^
+                       !test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags));
+               if (test_bit(RBD_DEV_FLAG_BLACKLISTED, &rbd_dev->flags)) {
+                       result = -EBLACKLISTED;
+                       goto err_unlock;
+               }
        }
 
        img_request = rbd_img_request_create(rbd_dev, offset, length, op_type,
index 2dc5c96c186aa3455ea124aa2bb824e889e1e15f..5545a679abd8887123fc83d57beb37dede77a685 100644 (file)
@@ -376,7 +376,7 @@ static void virtblk_config_changed(struct virtio_device *vdev)
 
 static int init_vq(struct virtio_blk *vblk)
 {
-       int err = 0;
+       int err;
        int i;
        vq_callback_t **callbacks;
        const char **names;
@@ -390,13 +390,13 @@ static int init_vq(struct virtio_blk *vblk)
        if (err)
                num_vqs = 1;
 
-       vblk->vqs = kmalloc(sizeof(*vblk->vqs) * num_vqs, GFP_KERNEL);
+       vblk->vqs = kmalloc_array(num_vqs, sizeof(*vblk->vqs), GFP_KERNEL);
        if (!vblk->vqs)
                return -ENOMEM;
 
-       names = kmalloc(sizeof(*names) * num_vqs, GFP_KERNEL);
-       callbacks = kmalloc(sizeof(*callbacks) * num_vqs, GFP_KERNEL);
-       vqs = kmalloc(sizeof(*vqs) * num_vqs, GFP_KERNEL);
+       names = kmalloc_array(num_vqs, sizeof(*names), GFP_KERNEL);
+       callbacks = kmalloc_array(num_vqs, sizeof(*callbacks), GFP_KERNEL);
+       vqs = kmalloc_array(num_vqs, sizeof(*vqs), GFP_KERNEL);
        if (!names || !callbacks || !vqs) {
                err = -ENOMEM;
                goto out;
index 04365b17ee67fe668f4bfc1f5683846af999009a..5497f7fc44d04c0287a6c51d968a7df0165a37c3 100644 (file)
@@ -1403,7 +1403,8 @@ static ssize_t hot_remove_store(struct class *class,
        zram = idr_find(&zram_index_idr, dev_id);
        if (zram) {
                ret = zram_remove(zram);
-               idr_remove(&zram_index_idr, dev_id);
+               if (!ret)
+                       idr_remove(&zram_index_idr, dev_id);
        } else {
                ret = -ENODEV;
        }
@@ -1412,8 +1413,14 @@ static ssize_t hot_remove_store(struct class *class,
        return ret ? ret : count;
 }
 
+/*
+ * NOTE: hot_add attribute is not the usual read-only sysfs attribute. In a
+ * sense that reading from this file does alter the state of your system -- it
+ * creates a new un-initialized zram device and returns back this device's
+ * device_id (or an error code if it fails to create a new device).
+ */
 static struct class_attribute zram_control_class_attrs[] = {
-       __ATTR_RO(hot_add),
+       __ATTR(hot_add, 0400, hot_add_show, NULL),
        __ATTR_WO(hot_remove),
        __ATTR_NULL,
 };
index ef51c9c864c59e2ae0cfa89f2dede3b282d4830e..b6bb58c41df5b7c553e6bfd05d7c8ce3adece509 100644 (file)
@@ -310,7 +310,7 @@ static int bt_ti_probe(struct platform_device *pdev)
        BT_DBG("HCI device registered (hdev %p)", hdev);
 
        dev_set_drvdata(&pdev->dev, hst);
-       return err;
+       return 0;
 }
 
 static int bt_ti_remove(struct platform_device *pdev)
index 5ccb90ef0146e5f324dd6da2590bea6a19a37521..8f6c23c20c52d83b4097dabfa64b82d6b360cf4b 100644 (file)
@@ -643,6 +643,14 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
                },
                .driver_data = &acpi_active_low,
        },
+       {       /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */
+               .ident = "Lenovo ThinkPad 8",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"),
+               },
+               .driver_data = &acpi_active_low,
+       },
        { }
 };
 
index 7010dcac93288aa1984ea9d7d232bdd163e4d37a..78751057164aedfe29b270a69d10c7c6f7b3b73a 100644 (file)
@@ -111,6 +111,7 @@ config OMAP_OCP2SCP
 config QCOM_EBI2
        bool "Qualcomm External Bus Interface 2 (EBI2)"
        depends on HAS_IOMEM
+       depends on ARCH_QCOM || COMPILE_TEST
        help
          Say y here to enable support for the Qualcomm External Bus
          Interface 2, which can be used to connect things like NAND Flash,
index 482794526e8cd52418dc1c1e6e5b200943d3c4c8..d2d2c89de5b4428e627eb06d9733ec1bcf2c2b0d 100644 (file)
@@ -84,14 +84,14 @@ static size_t rng_buffer_size(void)
 
 static void add_early_randomness(struct hwrng *rng)
 {
-       unsigned char bytes[16];
        int bytes_read;
+       size_t size = min_t(size_t, 16, rng_buffer_size());
 
        mutex_lock(&reading_mutex);
-       bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1);
+       bytes_read = rng_get_data(rng, rng_buffer, size, 1);
        mutex_unlock(&reading_mutex);
        if (bytes_read > 0)
-               add_device_randomness(bytes, bytes_read);
+               add_device_randomness(rng_buffer, bytes_read);
 }
 
 static inline void cleanup_rng(struct kref *kref)
index 5a9350b1069a3495b2d1e4d116fcb2d780bbd9d2..7f816655cbbfafc9ea3f16097ba4a6f8a0f4b91b 100644 (file)
@@ -76,3 +76,11 @@ config IPMI_POWEROFF
         the IPMI management controller is capable of this.
 
 endif # IPMI_HANDLER
+
+config ASPEED_BT_IPMI_BMC
+       depends on ARCH_ASPEED
+       tristate "BT IPMI bmc driver"
+       help
+         Provides a driver for the BT (Block Transfer) IPMI interface
+         found on Aspeed SOCs (AST2400 and AST2500). The driver
+         implements the BMC side of the BT interface.
index f3ffde1f5f1f53c3c702458b5e2d33f84866e0b9..0d98cd91def1dba3f70f8aae98d01bc04522c8b1 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o
 obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
 obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
 obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
+obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
new file mode 100644 (file)
index 0000000..fc9e889
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2015-2016, IBM Corporation.
+ *
+ * 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/atomic.h>
+#include <linux/bt-bmc.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+/*
+ * This is a BMC device used to communicate to the host
+ */
+#define DEVICE_NAME    "ipmi-bt-host"
+
+#define BT_IO_BASE     0xe4
+#define BT_IRQ         10
+
+#define BT_CR0         0x0
+#define   BT_CR0_IO_BASE               16
+#define   BT_CR0_IRQ                   12
+#define   BT_CR0_EN_CLR_SLV_RDP                0x8
+#define   BT_CR0_EN_CLR_SLV_WRP                0x4
+#define   BT_CR0_ENABLE_IBT            0x1
+#define BT_CR1         0x4
+#define   BT_CR1_IRQ_H2B       0x01
+#define   BT_CR1_IRQ_HBUSY     0x40
+#define BT_CR2         0x8
+#define   BT_CR2_IRQ_H2B       0x01
+#define   BT_CR2_IRQ_HBUSY     0x40
+#define BT_CR3         0xc
+#define BT_CTRL                0x10
+#define   BT_CTRL_B_BUSY               0x80
+#define   BT_CTRL_H_BUSY               0x40
+#define   BT_CTRL_OEM0                 0x20
+#define   BT_CTRL_SMS_ATN              0x10
+#define   BT_CTRL_B2H_ATN              0x08
+#define   BT_CTRL_H2B_ATN              0x04
+#define   BT_CTRL_CLR_RD_PTR           0x02
+#define   BT_CTRL_CLR_WR_PTR           0x01
+#define BT_BMC2HOST    0x14
+#define BT_INTMASK     0x18
+#define   BT_INTMASK_B2H_IRQEN         0x01
+#define   BT_INTMASK_B2H_IRQ           0x02
+#define   BT_INTMASK_BMC_HWRST         0x80
+
+#define BT_BMC_BUFFER_SIZE 256
+
+struct bt_bmc {
+       struct device           dev;
+       struct miscdevice       miscdev;
+       void __iomem            *base;
+       int                     irq;
+       wait_queue_head_t       queue;
+       struct timer_list       poll_timer;
+       struct mutex            mutex;
+};
+
+static atomic_t open_count = ATOMIC_INIT(0);
+
+static u8 bt_inb(struct bt_bmc *bt_bmc, int reg)
+{
+       return ioread8(bt_bmc->base + reg);
+}
+
+static void bt_outb(struct bt_bmc *bt_bmc, u8 data, int reg)
+{
+       iowrite8(data, bt_bmc->base + reg);
+}
+
+static void clr_rd_ptr(struct bt_bmc *bt_bmc)
+{
+       bt_outb(bt_bmc, BT_CTRL_CLR_RD_PTR, BT_CTRL);
+}
+
+static void clr_wr_ptr(struct bt_bmc *bt_bmc)
+{
+       bt_outb(bt_bmc, BT_CTRL_CLR_WR_PTR, BT_CTRL);
+}
+
+static void clr_h2b_atn(struct bt_bmc *bt_bmc)
+{
+       bt_outb(bt_bmc, BT_CTRL_H2B_ATN, BT_CTRL);
+}
+
+static void set_b_busy(struct bt_bmc *bt_bmc)
+{
+       if (!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_B_BUSY))
+               bt_outb(bt_bmc, BT_CTRL_B_BUSY, BT_CTRL);
+}
+
+static void clr_b_busy(struct bt_bmc *bt_bmc)
+{
+       if (bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_B_BUSY)
+               bt_outb(bt_bmc, BT_CTRL_B_BUSY, BT_CTRL);
+}
+
+static void set_b2h_atn(struct bt_bmc *bt_bmc)
+{
+       bt_outb(bt_bmc, BT_CTRL_B2H_ATN, BT_CTRL);
+}
+
+static u8 bt_read(struct bt_bmc *bt_bmc)
+{
+       return bt_inb(bt_bmc, BT_BMC2HOST);
+}
+
+static ssize_t bt_readn(struct bt_bmc *bt_bmc, u8 *buf, size_t n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               buf[i] = bt_read(bt_bmc);
+       return n;
+}
+
+static void bt_write(struct bt_bmc *bt_bmc, u8 c)
+{
+       bt_outb(bt_bmc, c, BT_BMC2HOST);
+}
+
+static ssize_t bt_writen(struct bt_bmc *bt_bmc, u8 *buf, size_t n)
+{
+       int i;
+
+       for (i = 0; i < n; i++)
+               bt_write(bt_bmc, buf[i]);
+       return n;
+}
+
+static void set_sms_atn(struct bt_bmc *bt_bmc)
+{
+       bt_outb(bt_bmc, BT_CTRL_SMS_ATN, BT_CTRL);
+}
+
+static struct bt_bmc *file_bt_bmc(struct file *file)
+{
+       return container_of(file->private_data, struct bt_bmc, miscdev);
+}
+
+static int bt_bmc_open(struct inode *inode, struct file *file)
+{
+       struct bt_bmc *bt_bmc = file_bt_bmc(file);
+
+       if (atomic_inc_return(&open_count) == 1) {
+               clr_b_busy(bt_bmc);
+               return 0;
+       }
+
+       atomic_dec(&open_count);
+       return -EBUSY;
+}
+
+/*
+ * The BT (Block Transfer) interface means that entire messages are
+ * buffered by the host before a notification is sent to the BMC that
+ * there is data to be read. The first byte is the length and the
+ * message data follows. The read operation just tries to capture the
+ * whole before returning it to userspace.
+ *
+ * BT Message format :
+ *
+ *    Byte 1  Byte 2     Byte 3  Byte 4  Byte 5:N
+ *    Length  NetFn/LUN  Seq     Cmd     Data
+ *
+ */
+static ssize_t bt_bmc_read(struct file *file, char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       struct bt_bmc *bt_bmc = file_bt_bmc(file);
+       u8 len;
+       int len_byte = 1;
+       u8 kbuffer[BT_BMC_BUFFER_SIZE];
+       ssize_t ret = 0;
+       ssize_t nread;
+
+       if (!access_ok(VERIFY_WRITE, buf, count))
+               return -EFAULT;
+
+       WARN_ON(*ppos);
+
+       if (wait_event_interruptible(bt_bmc->queue,
+                                    bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))
+               return -ERESTARTSYS;
+
+       mutex_lock(&bt_bmc->mutex);
+
+       if (unlikely(!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))) {
+               ret = -EIO;
+               goto out_unlock;
+       }
+
+       set_b_busy(bt_bmc);
+       clr_h2b_atn(bt_bmc);
+       clr_rd_ptr(bt_bmc);
+
+       /*
+        * The BT frames start with the message length, which does not
+        * include the length byte.
+        */
+       kbuffer[0] = bt_read(bt_bmc);
+       len = kbuffer[0];
+
+       /* We pass the length back to userspace as well */
+       if (len + 1 > count)
+               len = count - 1;
+
+       while (len) {
+               nread = min_t(ssize_t, len, sizeof(kbuffer) - len_byte);
+
+               bt_readn(bt_bmc, kbuffer + len_byte, nread);
+
+               if (copy_to_user(buf, kbuffer, nread + len_byte)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               len -= nread;
+               buf += nread + len_byte;
+               ret += nread + len_byte;
+               len_byte = 0;
+       }
+
+       clr_b_busy(bt_bmc);
+
+out_unlock:
+       mutex_unlock(&bt_bmc->mutex);
+       return ret;
+}
+
+/*
+ * BT Message response format :
+ *
+ *    Byte 1  Byte 2     Byte 3  Byte 4  Byte 5  Byte 6:N
+ *    Length  NetFn/LUN  Seq     Cmd     Code    Data
+ */
+static ssize_t bt_bmc_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       struct bt_bmc *bt_bmc = file_bt_bmc(file);
+       u8 kbuffer[BT_BMC_BUFFER_SIZE];
+       ssize_t ret = 0;
+       ssize_t nwritten;
+
+       /*
+        * send a minimum response size
+        */
+       if (count < 5)
+               return -EINVAL;
+
+       if (!access_ok(VERIFY_READ, buf, count))
+               return -EFAULT;
+
+       WARN_ON(*ppos);
+
+       /*
+        * There's no interrupt for clearing bmc busy so we have to
+        * poll
+        */
+       if (wait_event_interruptible(bt_bmc->queue,
+                                    !(bt_inb(bt_bmc, BT_CTRL) &
+                                      (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))))
+               return -ERESTARTSYS;
+
+       mutex_lock(&bt_bmc->mutex);
+
+       if (unlikely(bt_inb(bt_bmc, BT_CTRL) &
+                    (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))) {
+               ret = -EIO;
+               goto out_unlock;
+       }
+
+       clr_wr_ptr(bt_bmc);
+
+       while (count) {
+               nwritten = min_t(ssize_t, count, sizeof(kbuffer));
+               if (copy_from_user(&kbuffer, buf, nwritten)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               bt_writen(bt_bmc, kbuffer, nwritten);
+
+               count -= nwritten;
+               buf += nwritten;
+               ret += nwritten;
+       }
+
+       set_b2h_atn(bt_bmc);
+
+out_unlock:
+       mutex_unlock(&bt_bmc->mutex);
+       return ret;
+}
+
+static long bt_bmc_ioctl(struct file *file, unsigned int cmd,
+                        unsigned long param)
+{
+       struct bt_bmc *bt_bmc = file_bt_bmc(file);
+
+       switch (cmd) {
+       case BT_BMC_IOCTL_SMS_ATN:
+               set_sms_atn(bt_bmc);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int bt_bmc_release(struct inode *inode, struct file *file)
+{
+       struct bt_bmc *bt_bmc = file_bt_bmc(file);
+
+       atomic_dec(&open_count);
+       set_b_busy(bt_bmc);
+       return 0;
+}
+
+static unsigned int bt_bmc_poll(struct file *file, poll_table *wait)
+{
+       struct bt_bmc *bt_bmc = file_bt_bmc(file);
+       unsigned int mask = 0;
+       u8 ctrl;
+
+       poll_wait(file, &bt_bmc->queue, wait);
+
+       ctrl = bt_inb(bt_bmc, BT_CTRL);
+
+       if (ctrl & BT_CTRL_H2B_ATN)
+               mask |= POLLIN;
+
+       if (!(ctrl & (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN)))
+               mask |= POLLOUT;
+
+       return mask;
+}
+
+static const struct file_operations bt_bmc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = bt_bmc_open,
+       .read           = bt_bmc_read,
+       .write          = bt_bmc_write,
+       .release        = bt_bmc_release,
+       .poll           = bt_bmc_poll,
+       .unlocked_ioctl = bt_bmc_ioctl,
+};
+
+static void poll_timer(unsigned long data)
+{
+       struct bt_bmc *bt_bmc = (void *)data;
+
+       bt_bmc->poll_timer.expires += msecs_to_jiffies(500);
+       wake_up(&bt_bmc->queue);
+       add_timer(&bt_bmc->poll_timer);
+}
+
+static irqreturn_t bt_bmc_irq(int irq, void *arg)
+{
+       struct bt_bmc *bt_bmc = arg;
+       u32 reg;
+
+       reg = ioread32(bt_bmc->base + BT_CR2);
+       reg &= BT_CR2_IRQ_H2B | BT_CR2_IRQ_HBUSY;
+       if (!reg)
+               return IRQ_NONE;
+
+       /* ack pending IRQs */
+       iowrite32(reg, bt_bmc->base + BT_CR2);
+
+       wake_up(&bt_bmc->queue);
+       return IRQ_HANDLED;
+}
+
+static int bt_bmc_config_irq(struct bt_bmc *bt_bmc,
+                            struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       u32 reg;
+       int rc;
+
+       bt_bmc->irq = platform_get_irq(pdev, 0);
+       if (!bt_bmc->irq)
+               return -ENODEV;
+
+       rc = devm_request_irq(dev, bt_bmc->irq, bt_bmc_irq, IRQF_SHARED,
+                             DEVICE_NAME, bt_bmc);
+       if (rc < 0) {
+               dev_warn(dev, "Unable to request IRQ %d\n", bt_bmc->irq);
+               bt_bmc->irq = 0;
+               return rc;
+       }
+
+       /*
+        * Configure IRQs on the bmc clearing the H2B and HBUSY bits;
+        * H2B will be asserted when the bmc has data for us; HBUSY
+        * will be cleared (along with B2H) when we can write the next
+        * message to the BT buffer
+        */
+       reg = ioread32(bt_bmc->base + BT_CR1);
+       reg |= BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY;
+       iowrite32(reg, bt_bmc->base + BT_CR1);
+
+       return 0;
+}
+
+static int bt_bmc_probe(struct platform_device *pdev)
+{
+       struct bt_bmc *bt_bmc;
+       struct device *dev;
+       struct resource *res;
+       int rc;
+
+       if (!pdev || !pdev->dev.of_node)
+               return -ENODEV;
+
+       dev = &pdev->dev;
+       dev_info(dev, "Found bt bmc device\n");
+
+       bt_bmc = devm_kzalloc(dev, sizeof(*bt_bmc), GFP_KERNEL);
+       if (!bt_bmc)
+               return -ENOMEM;
+
+       dev_set_drvdata(&pdev->dev, bt_bmc);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       bt_bmc->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(bt_bmc->base))
+               return PTR_ERR(bt_bmc->base);
+
+       mutex_init(&bt_bmc->mutex);
+       init_waitqueue_head(&bt_bmc->queue);
+
+       bt_bmc->miscdev.minor   = MISC_DYNAMIC_MINOR,
+               bt_bmc->miscdev.name    = DEVICE_NAME,
+               bt_bmc->miscdev.fops    = &bt_bmc_fops,
+               bt_bmc->miscdev.parent = dev;
+       rc = misc_register(&bt_bmc->miscdev);
+       if (rc) {
+               dev_err(dev, "Unable to register misc device\n");
+               return rc;
+       }
+
+       bt_bmc_config_irq(bt_bmc, pdev);
+
+       if (bt_bmc->irq) {
+               dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
+       } else {
+               dev_info(dev, "No IRQ; using timer\n");
+               setup_timer(&bt_bmc->poll_timer, poll_timer,
+                           (unsigned long)bt_bmc);
+               bt_bmc->poll_timer.expires = jiffies + msecs_to_jiffies(10);
+               add_timer(&bt_bmc->poll_timer);
+       }
+
+       iowrite32((BT_IO_BASE << BT_CR0_IO_BASE) |
+                 (BT_IRQ << BT_CR0_IRQ) |
+                 BT_CR0_EN_CLR_SLV_RDP |
+                 BT_CR0_EN_CLR_SLV_WRP |
+                 BT_CR0_ENABLE_IBT,
+                 bt_bmc->base + BT_CR0);
+
+       clr_b_busy(bt_bmc);
+
+       return 0;
+}
+
+static int bt_bmc_remove(struct platform_device *pdev)
+{
+       struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
+
+       misc_deregister(&bt_bmc->miscdev);
+       if (!bt_bmc->irq)
+               del_timer_sync(&bt_bmc->poll_timer);
+       return 0;
+}
+
+static const struct of_device_id bt_bmc_match[] = {
+       { .compatible = "aspeed,ast2400-ibt-bmc" },
+       { },
+};
+
+static struct platform_driver bt_bmc_driver = {
+       .driver = {
+               .name           = DEVICE_NAME,
+               .of_match_table = bt_bmc_match,
+       },
+       .probe = bt_bmc_probe,
+       .remove = bt_bmc_remove,
+};
+
+module_platform_driver(bt_bmc_driver);
+
+MODULE_DEVICE_TABLE(of, bt_bmc_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alistair Popple <alistair@popple.id.au>");
+MODULE_DESCRIPTION("Linux device interface to the IPMI BT interface");
index d8619998cfb57ffffa9fa29e80498072d390db86..fcdd886819f5c85d88767d9d2042b8fef7a1d11f 100644 (file)
@@ -2891,11 +2891,11 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
                intf->curr_channel = IPMI_MAX_CHANNELS;
        }
 
+       rv = ipmi_bmc_register(intf, i);
+
        if (rv == 0)
                rv = add_proc_entries(intf, i);
 
-       rv = ipmi_bmc_register(intf, i);
-
  out:
        if (rv) {
                if (intf->proc_dir)
@@ -2982,8 +2982,6 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
        int intf_num = intf->intf_num;
        ipmi_user_t user;
 
-       ipmi_bmc_unregister(intf);
-
        mutex_lock(&smi_watchers_mutex);
        mutex_lock(&ipmi_interfaces_mutex);
        intf->intf_num = -1;
@@ -3007,6 +3005,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
        mutex_unlock(&ipmi_interfaces_mutex);
 
        remove_proc_entries(intf);
+       ipmi_bmc_unregister(intf);
 
        /*
         * Call all the watcher interfaces to tell them that
index d23368874710f726d485917e4d3f1ef93f3e3843..6af1ce04b3dac9ab1fd2e20d52d1930e6798502b 100644 (file)
@@ -748,10 +748,7 @@ static int pp_release(struct inode *inode, struct file *file)
        }
 
        if (pp->pdev) {
-               const char *name = pp->pdev->name;
-
                parport_unregister_device(pp->pdev);
-               kfree(name);
                pp->pdev = NULL;
                pr_debug(CHRDEV "%x: unregistered pardevice\n", minor);
        }
index 8de61876f6336bc2bd239ce935191b0b4c01eca4..3a9149cf011048f21fa742785c9ff0b6f9da6c0b 100644 (file)
@@ -813,9 +813,6 @@ int tpm_do_selftest(struct tpm_chip *chip)
                        continue;
                }
 
-               if (rc < TPM_HEADER_SIZE)
-                       return -EFAULT;
-
                if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
                        dev_info(&chip->dev,
                                 "TPM is disabled/deactivated (0x%X)\n", rc);
index d433b1db1fdd79469ae7b744cf8f2514c3a0fab0..5649234b73162aaefcb0d74a5f7b9ec4820be486 100644 (file)
@@ -1539,19 +1539,29 @@ static void remove_port_data(struct port *port)
        spin_lock_irq(&port->inbuf_lock);
        /* Remove unused data this port might have received. */
        discard_port_data(port);
+       spin_unlock_irq(&port->inbuf_lock);
 
        /* Remove buffers we queued up for the Host to send us data in. */
-       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf, true);
-       spin_unlock_irq(&port->inbuf_lock);
+       do {
+               spin_lock_irq(&port->inbuf_lock);
+               buf = virtqueue_detach_unused_buf(port->in_vq);
+               spin_unlock_irq(&port->inbuf_lock);
+               if (buf)
+                       free_buf(buf, true);
+       } while (buf);
 
        spin_lock_irq(&port->outvq_lock);
        reclaim_consumed_buffers(port);
+       spin_unlock_irq(&port->outvq_lock);
 
        /* Free pending buffers from the out-queue. */
-       while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
-               free_buf(buf, true);
-       spin_unlock_irq(&port->outvq_lock);
+       do {
+               spin_lock_irq(&port->outvq_lock);
+               buf = virtqueue_detach_unused_buf(port->out_vq);
+               spin_unlock_irq(&port->outvq_lock);
+               if (buf)
+                       free_buf(buf, true);
+       } while (buf);
 }
 
 /*
index 190122e64a3a5e78079423c4f08f96a7ac52a1b2..85a449cf61e3fa79b36849f84a831e05683d48dc 100644 (file)
@@ -203,7 +203,7 @@ at91_clk_register_programmable(struct regmap *regmap,
        ret = clk_hw_register(NULL, &prog->hw);
        if (ret) {
                kfree(prog);
-               hw = &prog->hw;
+               hw = ERR_PTR(ret);
        }
 
        return hw;
index f21e9b7afd1ad3ab25f210ea0de59eabb5721015..e3eed5a784044c3db5e1260d82e7a200ff4b62e6 100644 (file)
@@ -20,7 +20,7 @@ config CLK_BCM_KONA
 
 config COMMON_CLK_IPROC
        bool "Broadcom iProc clock support"
-       depends on ARCH_BCM_IPROC || COMPILE_TEST
+       depends on ARCH_BCM_IPROC || ARCH_BCM_63XX || COMPILE_TEST
        depends on COMMON_CLK
        default ARCH_BCM_IPROC
        help
index b68bf573dcfb743a353f8312b67ec1585421f1f8..8c7763fd9efc52b30f02d9ebcd4fdb10d2876465 100644 (file)
@@ -502,8 +502,12 @@ static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate,
 static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate,
                                   unsigned long *parent_rate)
 {
+       struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
+       const struct bcm2835_pll_data *data = pll->data;
        u32 ndiv, fdiv;
 
+       rate = clamp(rate, data->min_rate, data->max_rate);
+
        bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv);
 
        return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1);
@@ -608,13 +612,6 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
        u32 ana[4];
        int i;
 
-       if (rate < data->min_rate || rate > data->max_rate) {
-               dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n",
-                       clk_hw_get_name(hw), rate,
-                       data->min_rate, data->max_rate);
-               return -EINVAL;
-       }
-
        if (rate > data->max_fb_rate) {
                use_fb_prediv = true;
                rate /= 2;
index edf3b96b3b737f0ec0aad0661bc0ded04177e58f..1d99292e2039ee5ff6e187e4e0cdbddf85d860e1 100644 (file)
@@ -685,7 +685,7 @@ static void __init berlin2_clock_setup(struct device_node *np)
        }
 
        /* register clk-provider */
-       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 
        return;
 
index 0718e831475fdace5f7bd0c06190147da1fb3870..3b784b593afde7fea97650f938b03c55c79d8ac0 100644 (file)
@@ -382,7 +382,7 @@ static void __init berlin2q_clock_setup(struct device_node *np)
        }
 
        /* register clk-provider */
-       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 
        return;
 
index 8802a2dd56ac415c1576d62eb8a0bff0c81c0f9e..f674778fb3ac5912e05fb7448c6b1fb21eefa3d8 100644 (file)
@@ -82,6 +82,6 @@ static void __init efm32gg_cmu_init(struct device_node *np)
        hws[clk_HFPERCLKDAC0] = clk_hw_register_gate(NULL, "HFPERCLK.DAC0",
                        "HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL);
 
-       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data);
+       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
 }
 CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init);
index b637f5979023f92659b2c6cd927f030a275b1532..eb953d3b0b69bef048312fe9b6ec3c2678d815bb 100644 (file)
@@ -216,6 +216,7 @@ static int max77686_clk_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       drv_data->num_clks = num_clks;
        drv_data->max_clk_data = devm_kcalloc(dev, num_clks,
                                              sizeof(*drv_data->max_clk_data),
                                              GFP_KERNEL);
index 20b105584f82fb9bad9ba17ec4b1a6136affc656..80ae2a51452d7410c1edc856f8126d6451c75913 100644 (file)
@@ -700,6 +700,7 @@ static struct clk * __init create_mux_common(struct clockgen *cg,
                                             struct mux_hwclock *hwc,
                                             const struct clk_ops *ops,
                                             unsigned long min_rate,
+                                            unsigned long max_rate,
                                             unsigned long pct80_rate,
                                             const char *fmt, int idx)
 {
@@ -728,6 +729,8 @@ static struct clk * __init create_mux_common(struct clockgen *cg,
                        continue;
                if (rate < min_rate)
                        continue;
+               if (rate > max_rate)
+                       continue;
 
                parent_names[j] = div->name;
                hwc->parent_to_clksel[j] = i;
@@ -759,7 +762,7 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
        struct mux_hwclock *hwc;
        const struct clockgen_pll_div *div;
        unsigned long plat_rate, min_rate;
-       u64 pct80_rate;
+       u64 max_rate, pct80_rate;
        u32 clksel;
 
        hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
@@ -787,8 +790,8 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
                return NULL;
        }
 
-       pct80_rate = clk_get_rate(div->clk);
-       pct80_rate *= 8;
+       max_rate = clk_get_rate(div->clk);
+       pct80_rate = max_rate * 8;
        do_div(pct80_rate, 10);
 
        plat_rate = clk_get_rate(cg->pll[PLATFORM_PLL].div[PLL_DIV1].clk);
@@ -798,7 +801,7 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
        else
                min_rate = plat_rate / 2;
 
-       return create_mux_common(cg, hwc, &cmux_ops, min_rate,
+       return create_mux_common(cg, hwc, &cmux_ops, min_rate, max_rate,
                                 pct80_rate, "cg-cmux%d", idx);
 }
 
@@ -813,7 +816,7 @@ static struct clk * __init create_one_hwaccel(struct clockgen *cg, int idx)
        hwc->reg = cg->regs + 0x20 * idx + 0x10;
        hwc->info = cg->info.hwaccel[idx];
 
-       return create_mux_common(cg, hwc, &hwaccel_ops, 0, 0,
+       return create_mux_common(cg, hwc, &hwaccel_ops, 0, ULONG_MAX, 0,
                                 "cg-hwaccel%d", idx);
 }
 
index 5daddf5ecc4b2ca403203d5e5cae5eabf825915f..bc37030e38ba62833316302a383d86cdfd671921 100644 (file)
@@ -463,22 +463,20 @@ static int xgene_clk_enable(struct clk_hw *hw)
        struct xgene_clk *pclk = to_xgene_clk(hw);
        unsigned long flags = 0;
        u32 data;
-       phys_addr_t reg;
 
        if (pclk->lock)
                spin_lock_irqsave(pclk->lock, flags);
 
        if (pclk->param.csr_reg != NULL) {
                pr_debug("%s clock enabled\n", clk_hw_get_name(hw));
-               reg = __pa(pclk->param.csr_reg);
                /* First enable the clock */
                data = xgene_clk_read(pclk->param.csr_reg +
                                        pclk->param.reg_clk_offset);
                data |= pclk->param.reg_clk_mask;
                xgene_clk_write(data, pclk->param.csr_reg +
                                        pclk->param.reg_clk_offset);
-               pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n",
-                       clk_hw_get_name(hw), &reg,
+               pr_debug("%s clk offset 0x%08X mask 0x%08X value 0x%08X\n",
+                       clk_hw_get_name(hw),
                        pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
                        data);
 
@@ -488,8 +486,8 @@ static int xgene_clk_enable(struct clk_hw *hw)
                data &= ~pclk->param.reg_csr_mask;
                xgene_clk_write(data, pclk->param.csr_reg +
                                        pclk->param.reg_csr_offset);
-               pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n",
-                       clk_hw_get_name(hw), &reg,
+               pr_debug("%s csr offset 0x%08X mask 0x%08X value 0x%08X\n",
+                       clk_hw_get_name(hw),
                        pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
                        data);
        }
index fe364e63f8de899867d2c6e8bb47394b8e871426..c0e8e1f196aae4f15c39bf39a725db8fd192f101 100644 (file)
@@ -195,7 +195,7 @@ static void __init hi6220_clk_sys_init(struct device_node *np)
        hi6220_clk_register_divider(hi6220_div_clks_sys,
                        ARRAY_SIZE(hi6220_div_clks_sys), clk_data);
 }
-CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init);
+CLK_OF_DECLARE_DRIVER(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init);
 
 
 /* clocks in media controller */
@@ -252,7 +252,7 @@ static void __init hi6220_clk_media_init(struct device_node *np)
        hi6220_clk_register_divider(hi6220_div_clks_media,
                                ARRAY_SIZE(hi6220_div_clks_media), clk_data);
 }
-CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init);
+CLK_OF_DECLARE_DRIVER(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init);
 
 
 /* clocks in pmctrl */
index 19f9b622981a5281bc375a756d437cc117c63640..7a6acc3e4a927c1ae874bdb74bbe826284602c3a 100644 (file)
@@ -223,7 +223,7 @@ static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw,
        temp64 *= mfn;
        do_div(temp64, mfd);
 
-       return (parent_rate * div) + (u32)temp64;
+       return parent_rate * div + (unsigned long)temp64;
 }
 
 static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -247,7 +247,11 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate,
        do_div(temp64, parent_rate);
        mfn = temp64;
 
-       return parent_rate * div + parent_rate * mfn / mfd;
+       temp64 = (u64)parent_rate;
+       temp64 *= mfn;
+       do_div(temp64, mfd);
+
+       return parent_rate * div + (unsigned long)temp64;
 }
 
 static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
index 380c372d528ec1b0ec593e00eb052547515208e8..f042bd2a6a998651481e7ca594333c3856f6d8dc 100644 (file)
@@ -8,6 +8,7 @@ config COMMON_CLK_MEDIATEK
 
 config COMMON_CLK_MT8135
        bool "Clock driver for Mediatek MT8135"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
        select COMMON_CLK_MEDIATEK
        default ARCH_MEDIATEK
        ---help---
@@ -15,6 +16,7 @@ config COMMON_CLK_MT8135
 
 config COMMON_CLK_MT8173
        bool "Clock driver for Mediatek MT8173"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
        select COMMON_CLK_MEDIATEK
        default ARCH_MEDIATEK
        ---help---
index 3a51fff1b0e76b7bbebdbc969d7f1d67fe796887..9adaf48aea2317625a520bb42635fa8362946893 100644 (file)
@@ -313,7 +313,7 @@ static void __init mmp2_clk_init(struct device_node *np)
        }
 
        pxa_unit->apmu_base = of_iomap(np, 1);
-       if (!pxa_unit->mpmu_base) {
+       if (!pxa_unit->apmu_base) {
                pr_err("failed to map apmu registers\n");
                return;
        }
index 87f2317b2a005aca6aed18a39de7509010edd19e..f110c02e83cb6142c0653357f4c13d05b0f17018 100644 (file)
@@ -262,7 +262,7 @@ static void __init pxa168_clk_init(struct device_node *np)
        }
 
        pxa_unit->apmu_base = of_iomap(np, 1);
-       if (!pxa_unit->mpmu_base) {
+       if (!pxa_unit->apmu_base) {
                pr_err("failed to map apmu registers\n");
                return;
        }
index e22a67f76d932546eba42aec3b69be266d775238..64d1ef49caebedd9d35226afcec9e0a624f0965f 100644 (file)
@@ -282,7 +282,7 @@ static void __init pxa910_clk_init(struct device_node *np)
        }
 
        pxa_unit->apmu_base = of_iomap(np, 1);
-       if (!pxa_unit->mpmu_base) {
+       if (!pxa_unit->apmu_base) {
                pr_err("failed to map apmu registers\n");
                return;
        }
@@ -294,7 +294,7 @@ static void __init pxa910_clk_init(struct device_node *np)
        }
 
        pxa_unit->apbcp_base = of_iomap(np, 3);
-       if (!pxa_unit->mpmu_base) {
+       if (!pxa_unit->apbcp_base) {
                pr_err("failed to map apbcp registers\n");
                return;
        }
index 45905fc0d75b3e650403da4aa83513322f630cea..cecb0fdfaef6cd354893f9f4628427c7dee655e5 100644 (file)
@@ -305,7 +305,7 @@ static const struct of_device_id armada_3700_periph_clock_of_match[] = {
 };
 static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
                                         void __iomem *reg, spinlock_t *lock,
-                                        struct device *dev, struct clk_hw *hw)
+                                        struct device *dev, struct clk_hw **hw)
 {
        const struct clk_ops *mux_ops = NULL, *gate_ops = NULL,
                *rate_ops = NULL;
@@ -329,6 +329,7 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
                gate->lock = lock;
                gate_ops = gate_hw->init->ops;
                gate->reg = reg + (u64)gate->reg;
+               gate->flags = CLK_GATE_SET_TO_DISABLE;
        }
 
        if (data->rate_hw) {
@@ -353,13 +354,13 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
                }
        }
 
-       hw = clk_hw_register_composite(dev, data->name, data->parent_names,
+       *hw = clk_hw_register_composite(dev, data->name, data->parent_names,
                                       data->num_parents, mux_hw,
                                       mux_ops, rate_hw, rate_ops,
                                       gate_hw, gate_ops, CLK_IGNORE_UNUSED);
 
-       if (IS_ERR(hw))
-               return PTR_ERR(hw);
+       if (IS_ERR(*hw))
+               return PTR_ERR(*hw);
 
        return 0;
 }
@@ -400,7 +401,7 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
        spin_lock_init(&driver_data->lock);
 
        for (i = 0; i < num_periph; i++) {
-               struct clk_hw *hw = driver_data->hw_data->hws[i];
+               struct clk_hw **hw = &driver_data->hw_data->hws[i];
 
                if (armada_3700_add_composite_clk(&data[i], reg,
                                                  &driver_data->lock, dev, hw))
index 8feba93672c5e4248a98c7116887995756bc77f5..e8075359366b0d9ef9cf84611d6c36b19fc22c4a 100644 (file)
@@ -144,11 +144,8 @@ struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
        ddrclk->ddr_flag = ddr_flag;
 
        clk = clk_register(NULL, &ddrclk->hw);
-       if (IS_ERR(clk)) {
-               pr_err("%s: could not register ddrclk %s\n", __func__,  name);
+       if (IS_ERR(clk))
                kfree(ddrclk);
-               return NULL;
-       }
 
        return clk;
 }
index 51d152f735cc5be186c9b0b1e2bf00cef2381b7b..17e68a724945608382924ce18b64f3df9d172db8 100644 (file)
@@ -106,6 +106,7 @@ static const struct of_device_id exynos_audss_clk_of_match[] = {
        },
        { },
 };
+MODULE_DEVICE_TABLE(of, exynos_audss_clk_of_match);
 
 static void exynos_audss_clk_teardown(void)
 {
index 96fab6cfb2027f805e8ed941012a464d58cbb3dd..6c6afb87b4ce3babf8d7625581a5f7a288b1a1d5 100644 (file)
@@ -132,28 +132,34 @@ free_clkout:
        pr_err("%s: failed to register clkout clock\n", __func__);
 }
 
+/*
+ * We use CLK_OF_DECLARE_DRIVER initialization method to avoid setting
+ * the OF_POPULATED flag on the pmu device tree node, so later the
+ * Exynos PMU platform device can be properly probed with PMU driver.
+ */
+
 static void __init exynos4_clkout_init(struct device_node *node)
 {
        exynos_clkout_init(node, EXYNOS4_CLKOUT_MUX_MASK);
 }
-CLK_OF_DECLARE(exynos4210_clkout, "samsung,exynos4210-pmu",
+CLK_OF_DECLARE_DRIVER(exynos4210_clkout, "samsung,exynos4210-pmu",
                exynos4_clkout_init);
-CLK_OF_DECLARE(exynos4212_clkout, "samsung,exynos4212-pmu",
+CLK_OF_DECLARE_DRIVER(exynos4212_clkout, "samsung,exynos4212-pmu",
                exynos4_clkout_init);
-CLK_OF_DECLARE(exynos4412_clkout, "samsung,exynos4412-pmu",
+CLK_OF_DECLARE_DRIVER(exynos4412_clkout, "samsung,exynos4412-pmu",
                exynos4_clkout_init);
-CLK_OF_DECLARE(exynos3250_clkout, "samsung,exynos3250-pmu",
+CLK_OF_DECLARE_DRIVER(exynos3250_clkout, "samsung,exynos3250-pmu",
                exynos4_clkout_init);
 
 static void __init exynos5_clkout_init(struct device_node *node)
 {
        exynos_clkout_init(node, EXYNOS5_CLKOUT_MUX_MASK);
 }
-CLK_OF_DECLARE(exynos5250_clkout, "samsung,exynos5250-pmu",
+CLK_OF_DECLARE_DRIVER(exynos5250_clkout, "samsung,exynos5250-pmu",
                exynos5_clkout_init);
-CLK_OF_DECLARE(exynos5410_clkout, "samsung,exynos5410-pmu",
+CLK_OF_DECLARE_DRIVER(exynos5410_clkout, "samsung,exynos5410-pmu",
                exynos5_clkout_init);
-CLK_OF_DECLARE(exynos5420_clkout, "samsung,exynos5420-pmu",
+CLK_OF_DECLARE_DRIVER(exynos5420_clkout, "samsung,exynos5420-pmu",
                exynos5_clkout_init);
-CLK_OF_DECLARE(exynos5433_clkout, "samsung,exynos5433-pmu",
+CLK_OF_DECLARE_DRIVER(exynos5433_clkout, "samsung,exynos5433-pmu",
                exynos5_clkout_init);
index 79596463e0d94b66a3135e7fe60d07cfcd023ad3..fc75a335a7ce12480f12f41a95091417466b6a92 100644 (file)
@@ -143,7 +143,7 @@ static SUNXI_CCU_NKM_WITH_MUX_GATE_LOCK(pll_mipi_clk, "pll-mipi",
                                        4, 2,   /* K */
                                        0, 4,   /* M */
                                        21, 0,  /* mux */
-                                       BIT(31),        /* gate */
+                                       BIT(31) | BIT(23) | BIT(22), /* gate */
                                        BIT(28),        /* lock */
                                        CLK_SET_RATE_UNGATE);
 
@@ -191,6 +191,8 @@ static struct clk_div_table axi_div_table[] = {
 static SUNXI_CCU_DIV_TABLE(axi_clk, "axi", "cpu",
                           0x050, 0, 3, axi_div_table, 0);
 
+#define SUN6I_A31_AHB1_REG  0x054
+
 static const char * const ahb1_parents[] = { "osc32k", "osc24M",
                                             "axi", "pll-periph" };
 
@@ -1230,6 +1232,16 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node)
        val &= BIT(16);
        writel(val, reg + SUN6I_A31_PLL_MIPI_REG);
 
+       /* Force AHB1 to PLL6 / 3 */
+       val = readl(reg + SUN6I_A31_AHB1_REG);
+       /* set PLL6 pre-div = 3 */
+       val &= ~GENMASK(7, 6);
+       val |= 0x2 << 6;
+       /* select PLL6 / pre-div */
+       val &= ~GENMASK(13, 12);
+       val |= 0x3 << 12;
+       writel(val, reg + SUN6I_A31_AHB1_REG);
+
        sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc);
 
        ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
index 96b40ca57697d0220452349dc83ff406099d11d7..9bd1f78a05471955890e41da51e1b81811c00d64 100644 (file)
@@ -131,7 +131,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_mipi_clk, "pll-mipi",
                                    8, 4,               /* N */
                                    4, 2,               /* K */
                                    0, 4,               /* M */
-                                   BIT(31),            /* gate */
+                                   BIT(31) | BIT(23) | BIT(22), /* gate */
                                    BIT(28),            /* lock */
                                    CLK_SET_RATE_UNGATE);
 
index 838b22aa8b67fbabdfef5386485d5c3316adf296..f2c9274b8bd570c586b56d10ec17e829e6a710c7 100644 (file)
@@ -373,7 +373,7 @@ static void sun4i_get_apb1_factors(struct factors_request *req)
        else
                calcp = 3;
 
-       calcm = (req->parent_rate >> calcp) - 1;
+       calcm = (div >> calcp) - 1;
 
        req->rate = (req->parent_rate >> calcp) / (calcm + 1);
        req->m = calcm;
index 5ffb898d0839df896ac7a82b266c46202bbdf0e9..26c53f7963a438dcaaac252229cea31419ab44ea 100644 (file)
@@ -79,7 +79,7 @@ static int uniphier_clk_probe(struct platform_device *pdev)
        hw_data->num = clk_num;
 
        /* avoid returning NULL for unused idx */
-       for (; clk_num >= 0; clk_num--)
+       while (--clk_num >= 0)
                hw_data->hws[clk_num] = ERR_PTR(-EINVAL);
 
        for (p = data; p->name; p++) {
@@ -110,6 +110,10 @@ static int uniphier_clk_remove(struct platform_device *pdev)
 
 static const struct of_device_id uniphier_clk_match[] = {
        /* System clock */
+       {
+               .compatible = "socionext,uniphier-sld3-clock",
+               .data = uniphier_sld3_sys_clk_data,
+       },
        {
                .compatible = "socionext,uniphier-ld4-clock",
                .data = uniphier_ld4_sys_clk_data,
@@ -138,7 +142,7 @@ static const struct of_device_id uniphier_clk_match[] = {
                .compatible = "socionext,uniphier-ld20-clock",
                .data = uniphier_ld20_sys_clk_data,
        },
-       /* Media I/O clock */
+       /* Media I/O clock, SD clock */
        {
                .compatible = "socionext,uniphier-sld3-mio-clock",
                .data = uniphier_sld3_mio_clk_data,
@@ -156,20 +160,20 @@ static const struct of_device_id uniphier_clk_match[] = {
                .data = uniphier_sld3_mio_clk_data,
        },
        {
-               .compatible = "socionext,uniphier-pro5-mio-clock",
-               .data = uniphier_pro5_mio_clk_data,
+               .compatible = "socionext,uniphier-pro5-sd-clock",
+               .data = uniphier_pro5_sd_clk_data,
        },
        {
-               .compatible = "socionext,uniphier-pxs2-mio-clock",
-               .data = uniphier_pro5_mio_clk_data,
+               .compatible = "socionext,uniphier-pxs2-sd-clock",
+               .data = uniphier_pro5_sd_clk_data,
        },
        {
                .compatible = "socionext,uniphier-ld11-mio-clock",
                .data = uniphier_sld3_mio_clk_data,
        },
        {
-               .compatible = "socionext,uniphier-ld20-mio-clock",
-               .data = uniphier_pro5_mio_clk_data,
+               .compatible = "socionext,uniphier-ld20-sd-clock",
+               .data = uniphier_pro5_sd_clk_data,
        },
        /* Peripheral clock */
        {
index 6aa7ec768d0bfad0141ed2ccc24611be6c34962e..218d20f099cec2da27eb2a80fc761b8b6b1c263e 100644 (file)
@@ -93,7 +93,7 @@ const struct uniphier_clk_data uniphier_sld3_mio_clk_data[] = {
        { /* sentinel */ }
 };
 
-const struct uniphier_clk_data uniphier_pro5_mio_clk_data[] = {
+const struct uniphier_clk_data uniphier_pro5_sd_clk_data[] = {
        UNIPHIER_MIO_CLK_SD_FIXED,
        UNIPHIER_MIO_CLK_SD(0, 0),
        UNIPHIER_MIO_CLK_SD(1, 1),
index 15a2f2cbe0d90e4ab5d68d4d9eb310bdf5164cf2..2c243a894f3b9fe19bd9575e2ca639f5939fa503 100644 (file)
@@ -42,7 +42,7 @@ static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw)
        struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
        int num_parents = clk_hw_get_num_parents(hw);
        int ret;
-       u32 val;
+       unsigned int val;
        u8 i;
 
        ret = regmap_read(mux->regmap, mux->reg, &val);
index 3ae184062388bf487be8b91c5b52193fd7383d75..0244dba1f4cf554567c37bd15978bd8813fc3be9 100644 (file)
@@ -115,7 +115,7 @@ extern const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[];
 extern const struct uniphier_clk_data uniphier_ld11_sys_clk_data[];
 extern const struct uniphier_clk_data uniphier_ld20_sys_clk_data[];
 extern const struct uniphier_clk_data uniphier_sld3_mio_clk_data[];
-extern const struct uniphier_clk_data uniphier_pro5_mio_clk_data[];
+extern const struct uniphier_clk_data uniphier_pro5_sd_clk_data[];
 extern const struct uniphier_clk_data uniphier_ld4_peri_clk_data[];
 extern const struct uniphier_clk_data uniphier_pro4_peri_clk_data[];
 
index 245190839359301edd5896e9bb2196c961a2847e..e2c6e43cf8ca31e27af1b6c8630f7a0c590e8b7a 100644 (file)
@@ -417,6 +417,16 @@ config SYS_SUPPORTS_SH_TMU
 config SYS_SUPPORTS_EM_STI
         bool
 
+config CLKSRC_JCORE_PIT
+       bool "J-Core PIT timer driver" if COMPILE_TEST
+       depends on OF
+       depends on GENERIC_CLOCKEVENTS
+       depends on HAS_IOMEM
+       select CLKSRC_MMIO
+       help
+         This enables build of clocksource and clockevent driver for
+         the integrated PIT in the J-Core synthesizable, open source SoC.
+
 config SH_TIMER_CMT
        bool "Renesas CMT timer driver" if COMPILE_TEST
        depends on GENERIC_CLOCKEVENTS
index fd9d6df0bbc0993c3b7862a08f89dc3a9725be9d..cf87f407f1adbfaab8d485bea93f6ee859d8e3d6 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_ATMEL_TCB_CLKSRC)  += tcb_clksrc.o
 obj-$(CONFIG_X86_PM_TIMER)     += acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)   += scx200_hrt.o
 obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)   += cs5535-clockevt.o
+obj-$(CONFIG_CLKSRC_JCORE_PIT)         += jcore-pit.o
 obj-$(CONFIG_SH_TIMER_CMT)     += sh_cmt.o
 obj-$(CONFIG_SH_TIMER_MTU2)    += sh_mtu2.o
 obj-$(CONFIG_SH_TIMER_TMU)     += sh_tmu.o
diff --git a/drivers/clocksource/jcore-pit.c b/drivers/clocksource/jcore-pit.c
new file mode 100644 (file)
index 0000000..54e1665
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * J-Core SoC PIT/clocksource driver
+ *
+ * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/sched_clock.h>
+#include <linux/cpu.h>
+#include <linux/cpuhotplug.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define PIT_IRQ_SHIFT          12
+#define PIT_PRIO_SHIFT         20
+#define PIT_ENABLE_SHIFT       26
+#define PIT_PRIO_MASK          0xf
+
+#define REG_PITEN              0x00
+#define REG_THROT              0x10
+#define REG_COUNT              0x14
+#define REG_BUSPD              0x18
+#define REG_SECHI              0x20
+#define REG_SECLO              0x24
+#define REG_NSEC               0x28
+
+struct jcore_pit {
+       struct clock_event_device       ced;
+       void __iomem                    *base;
+       unsigned long                   periodic_delta;
+       u32                             enable_val;
+};
+
+static void __iomem *jcore_pit_base;
+static struct jcore_pit __percpu *jcore_pit_percpu;
+
+static notrace u64 jcore_sched_clock_read(void)
+{
+       u32 seclo, nsec, seclo0;
+       __iomem void *base = jcore_pit_base;
+
+       seclo = readl(base + REG_SECLO);
+       do {
+               seclo0 = seclo;
+               nsec  = readl(base + REG_NSEC);
+               seclo = readl(base + REG_SECLO);
+       } while (seclo0 != seclo);
+
+       return seclo * NSEC_PER_SEC + nsec;
+}
+
+static cycle_t jcore_clocksource_read(struct clocksource *cs)
+{
+       return jcore_sched_clock_read();
+}
+
+static int jcore_pit_disable(struct jcore_pit *pit)
+{
+       writel(0, pit->base + REG_PITEN);
+       return 0;
+}
+
+static int jcore_pit_set(unsigned long delta, struct jcore_pit *pit)
+{
+       jcore_pit_disable(pit);
+       writel(delta, pit->base + REG_THROT);
+       writel(pit->enable_val, pit->base + REG_PITEN);
+       return 0;
+}
+
+static int jcore_pit_set_state_shutdown(struct clock_event_device *ced)
+{
+       struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
+
+       return jcore_pit_disable(pit);
+}
+
+static int jcore_pit_set_state_oneshot(struct clock_event_device *ced)
+{
+       struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
+
+       return jcore_pit_disable(pit);
+}
+
+static int jcore_pit_set_state_periodic(struct clock_event_device *ced)
+{
+       struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
+
+       return jcore_pit_set(pit->periodic_delta, pit);
+}
+
+static int jcore_pit_set_next_event(unsigned long delta,
+                                   struct clock_event_device *ced)
+{
+       struct jcore_pit *pit = container_of(ced, struct jcore_pit, ced);
+
+       return jcore_pit_set(delta, pit);
+}
+
+static int jcore_pit_local_init(unsigned cpu)
+{
+       struct jcore_pit *pit = this_cpu_ptr(jcore_pit_percpu);
+       unsigned buspd, freq;
+
+       pr_info("Local J-Core PIT init on cpu %u\n", cpu);
+
+       buspd = readl(pit->base + REG_BUSPD);
+       freq = DIV_ROUND_CLOSEST(NSEC_PER_SEC, buspd);
+       pit->periodic_delta = DIV_ROUND_CLOSEST(NSEC_PER_SEC, HZ * buspd);
+
+       clockevents_config_and_register(&pit->ced, freq, 1, ULONG_MAX);
+
+       return 0;
+}
+
+static irqreturn_t jcore_timer_interrupt(int irq, void *dev_id)
+{
+       struct jcore_pit *pit = this_cpu_ptr(dev_id);
+
+       if (clockevent_state_oneshot(&pit->ced))
+               jcore_pit_disable(pit);
+
+       pit->ced.event_handler(&pit->ced);
+
+       return IRQ_HANDLED;
+}
+
+static int __init jcore_pit_init(struct device_node *node)
+{
+       int err;
+       unsigned pit_irq, cpu;
+       unsigned long hwirq;
+       u32 irqprio, enable_val;
+
+       jcore_pit_base = of_iomap(node, 0);
+       if (!jcore_pit_base) {
+               pr_err("Error: Cannot map base address for J-Core PIT\n");
+               return -ENXIO;
+       }
+
+       pit_irq = irq_of_parse_and_map(node, 0);
+       if (!pit_irq) {
+               pr_err("Error: J-Core PIT has no IRQ\n");
+               return -ENXIO;
+       }
+
+       pr_info("Initializing J-Core PIT at %p IRQ %d\n",
+               jcore_pit_base, pit_irq);
+
+       err = clocksource_mmio_init(jcore_pit_base, "jcore_pit_cs",
+                                   NSEC_PER_SEC, 400, 32,
+                                   jcore_clocksource_read);
+       if (err) {
+               pr_err("Error registering clocksource device: %d\n", err);
+               return err;
+       }
+
+       sched_clock_register(jcore_sched_clock_read, 32, NSEC_PER_SEC);
+
+       jcore_pit_percpu = alloc_percpu(struct jcore_pit);
+       if (!jcore_pit_percpu) {
+               pr_err("Failed to allocate memory for clock event device\n");
+               return -ENOMEM;
+       }
+
+       err = request_irq(pit_irq, jcore_timer_interrupt,
+                         IRQF_TIMER | IRQF_PERCPU,
+                         "jcore_pit", jcore_pit_percpu);
+       if (err) {
+               pr_err("pit irq request failed: %d\n", err);
+               free_percpu(jcore_pit_percpu);
+               return err;
+       }
+
+       /*
+        * The J-Core PIT is not hard-wired to a particular IRQ, but
+        * integrated with the interrupt controller such that the IRQ it
+        * generates is programmable, as follows:
+        *
+        * The bit layout of the PIT enable register is:
+        *
+        *      .....e..ppppiiiiiiii............
+        *
+        * where the .'s indicate unrelated/unused bits, e is enable,
+        * p is priority, and i is hard irq number.
+        *
+        * For the PIT included in AIC1 (obsolete but still in use),
+        * any hard irq (trap number) can be programmed via the 8
+        * iiiiiiii bits, and a priority (0-15) is programmable
+        * separately in the pppp bits.
+        *
+        * For the PIT included in AIC2 (current), the programming
+        * interface is equivalent modulo interrupt mapping. This is
+        * why a different compatible tag was not used. However only
+        * traps 64-127 (the ones actually intended to be used for
+        * interrupts, rather than syscalls/exceptions/etc.) can be
+        * programmed (the high 2 bits of i are ignored) and the
+        * priority pppp is <<2'd and or'd onto the irq number. This
+        * choice seems to have been made on the hardware engineering
+        * side under an assumption that preserving old AIC1 priority
+        * mappings was important. Future models will likely ignore
+        * the pppp field.
+        */
+       hwirq = irq_get_irq_data(pit_irq)->hwirq;
+       irqprio = (hwirq >> 2) & PIT_PRIO_MASK;
+       enable_val = (1U << PIT_ENABLE_SHIFT)
+                  | (hwirq << PIT_IRQ_SHIFT)
+                  | (irqprio << PIT_PRIO_SHIFT);
+
+       for_each_present_cpu(cpu) {
+               struct jcore_pit *pit = per_cpu_ptr(jcore_pit_percpu, cpu);
+
+               pit->base = of_iomap(node, cpu);
+               if (!pit->base) {
+                       pr_err("Unable to map PIT for cpu %u\n", cpu);
+                       continue;
+               }
+
+               pit->ced.name = "jcore_pit";
+               pit->ced.features = CLOCK_EVT_FEAT_PERIODIC
+                                 | CLOCK_EVT_FEAT_ONESHOT
+                                 | CLOCK_EVT_FEAT_PERCPU;
+               pit->ced.cpumask = cpumask_of(cpu);
+               pit->ced.rating = 400;
+               pit->ced.irq = pit_irq;
+               pit->ced.set_state_shutdown = jcore_pit_set_state_shutdown;
+               pit->ced.set_state_periodic = jcore_pit_set_state_periodic;
+               pit->ced.set_state_oneshot = jcore_pit_set_state_oneshot;
+               pit->ced.set_next_event = jcore_pit_set_next_event;
+
+               pit->enable_val = enable_val;
+       }
+
+       cpuhp_setup_state(CPUHP_AP_JCORE_TIMER_STARTING,
+                         "AP_JCORE_TIMER_STARTING",
+                         jcore_pit_local_init, NULL);
+
+       return 0;
+}
+
+CLOCKSOURCE_OF_DECLARE(jcore_pit, "jcore,pit", jcore_pit_init);
index c184eb84101e9f9a72354baf4c87c4d2ada92d19..4f87f3e76d8328ec6ca462882f873a51b2f72995 100644 (file)
@@ -152,6 +152,13 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static cycle_t sun5i_clksrc_read(struct clocksource *clksrc)
+{
+       struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
+
+       return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1));
+}
+
 static int sun5i_rate_cb_clksrc(struct notifier_block *nb,
                                unsigned long event, void *data)
 {
@@ -210,8 +217,13 @@ static int __init sun5i_setup_clocksource(struct device_node *node,
        writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
               base + TIMER_CTL_REG(1));
 
-       ret = clocksource_mmio_init(base + TIMER_CNTVAL_LO_REG(1), node->name,
-                                   rate, 340, 32, clocksource_mmio_readl_down);
+       cs->clksrc.name = node->name;
+       cs->clksrc.rating = 340;
+       cs->clksrc.read = sun5i_clksrc_read;
+       cs->clksrc.mask = CLOCKSOURCE_MASK(32);
+       cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+       ret = clocksource_register_hz(&cs->clksrc, rate);
        if (ret) {
                pr_err("Couldn't register clock source.\n");
                goto err_remove_notifier;
index f535f812325841a683d5691fc61bd89860681229..4737520ec8230a830d80e81c0dbc9dbaa96d0dc7 100644 (file)
@@ -179,6 +179,7 @@ struct _pid {
 /**
  * struct cpudata -    Per CPU instance data storage
  * @cpu:               CPU number for this instance data
+ * @policy:            CPUFreq policy value
  * @update_util:       CPUFreq utility callback information
  * @update_util_set:   CPUFreq utility callback is set
  * @iowait_boost:      iowait-related boost fraction
@@ -201,6 +202,7 @@ struct _pid {
 struct cpudata {
        int cpu;
 
+       unsigned int policy;
        struct update_util_data update_util;
        bool   update_util_set;
 
@@ -1142,10 +1144,8 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
        *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
 }
 
-static void intel_pstate_set_min_pstate(struct cpudata *cpu)
+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
 {
-       int pstate = cpu->pstate.min_pstate;
-
        trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
        cpu->pstate.current_pstate = pstate;
        /*
@@ -1157,6 +1157,20 @@ static void intel_pstate_set_min_pstate(struct cpudata *cpu)
                      pstate_funcs.get_val(cpu, pstate));
 }
 
+static void intel_pstate_set_min_pstate(struct cpudata *cpu)
+{
+       intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+}
+
+static void intel_pstate_max_within_limits(struct cpudata *cpu)
+{
+       int min_pstate, max_pstate;
+
+       update_turbo_state();
+       intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate);
+       intel_pstate_set_pstate(cpu, max_pstate);
+}
+
 static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
 {
        cpu->pstate.min_pstate = pstate_funcs.get_min();
@@ -1325,7 +1339,8 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
 
        from = cpu->pstate.current_pstate;
 
-       target_pstate = pstate_funcs.get_target_pstate(cpu);
+       target_pstate = cpu->policy == CPUFREQ_POLICY_PERFORMANCE ?
+               cpu->pstate.turbo_pstate : pstate_funcs.get_target_pstate(cpu);
 
        intel_pstate_update_pstate(cpu, target_pstate);
 
@@ -1491,7 +1506,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
        pr_debug("set_policy cpuinfo.max %u policy->max %u\n",
                 policy->cpuinfo.max_freq, policy->max);
 
-       cpu = all_cpu_data[0];
+       cpu = all_cpu_data[policy->cpu];
+       cpu->policy = policy->policy;
+
        if (cpu->pstate.max_pstate_physical > cpu->pstate.max_pstate &&
            policy->max < policy->cpuinfo.max_freq &&
            policy->max > cpu->pstate.max_pstate * cpu->pstate.scaling) {
@@ -1499,7 +1516,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
                policy->max = policy->cpuinfo.max_freq;
        }
 
-       if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
+       if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) {
                limits = &performance_limits;
                if (policy->max >= policy->cpuinfo.max_freq) {
                        pr_debug("set performance\n");
@@ -1535,6 +1552,15 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
        limits->max_perf = round_up(limits->max_perf, FRAC_BITS);
 
  out:
+       if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) {
+               /*
+                * NOHZ_FULL CPUs need this as the governor callback may not
+                * be invoked on them.
+                */
+               intel_pstate_clear_update_util_hook(policy->cpu);
+               intel_pstate_max_within_limits(cpu);
+       }
+
        intel_pstate_set_update_util_hook(policy->cpu);
 
        intel_pstate_hwp_set_policy(policy);
index 156aad167cd6fcd44e66ea9456e253f8e3e36866..954a64c7757b10e1551672861a6ef28623e57019 100644 (file)
@@ -137,7 +137,7 @@ static void dbg_dump_sg(const char *level, const char *prefix_str,
                }
 
                buf = it_page + it->offset;
-               len = min(tlen, it->length);
+               len = min_t(size_t, tlen, it->length);
                print_hex_dump(level, prefix_str, prefix_type, rowsize,
                               groupsize, buf, len, ascii);
                tlen -= len;
@@ -4583,6 +4583,15 @@ static int __init caam_algapi_init(void)
                if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES))
                                continue;
 
+               /*
+                * Check support for AES modes not available
+                * on LP devices.
+                */
+               if ((cha_vid & CHA_ID_LS_AES_MASK) == CHA_ID_LS_AES_LP)
+                       if ((alg->class1_alg_type & OP_ALG_AAI_MASK) ==
+                            OP_ALG_AAI_XTS)
+                               continue;
+
                t_alg = caam_alg_alloc(alg);
                if (IS_ERR(t_alg)) {
                        err = PTR_ERR(t_alg);
index 72ff196589851d652ff4d369bf0ce497aa0e2165..e483b78c6343fd745f83e52b317edbb3ccb23e92 100644 (file)
@@ -558,8 +558,9 @@ static int caam_probe(struct platform_device *pdev)
         * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
         * long pointers in master configuration register
         */
-       clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK, MCFGR_AWCACHE_CACH |
-                     MCFGR_AWCACHE_BUFF | MCFGR_WDENABLE | MCFGR_LARGE_BURST |
+       clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR,
+                     MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF |
+                     MCFGR_WDENABLE | MCFGR_LARGE_BURST |
                      (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0));
 
        /*
index ec64fbcdeb49230d10fce5cda83dc238dbb45500..199b0bb69b89bcd5c96af1a9355208b367737089 100644 (file)
@@ -422,7 +422,7 @@ static inline void get_aes_decrypt_key(unsigned char *dec_key,
 {
        u32 temp;
        u32 w_ring[MAX_NK];
-       int i, j, k = 0;
+       int i, j, k;
        u8  nr, nk;
 
        switch (keylength) {
@@ -460,6 +460,7 @@ static inline void get_aes_decrypt_key(unsigned char *dec_key,
                temp = w_ring[i % nk];
                i++;
        }
+       i--;
        for (k = 0, j = i % nk; k < nk; k++) {
                *((u32 *)dec_key + k) = htonl(w_ring[j]);
                j--;
index 9f284682c091aa1b675ea5a1fdda806a5345935c..77712b375b8428a88ad127d689a4e3a99e6b0640 100644 (file)
@@ -168,12 +168,11 @@ static void mv_cesa_ahash_std_step(struct ahash_request *req)
        mv_cesa_adjust_op(engine, &creq->op_tmpl);
        memcpy_toio(engine->sram, &creq->op_tmpl, sizeof(creq->op_tmpl));
 
-       digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
-       for (i = 0; i < digsize / 4; i++)
-               writel_relaxed(creq->state[i], engine->regs + CESA_IVDIG(i));
-
-       mv_cesa_adjust_op(engine, &creq->op_tmpl);
-       memcpy_toio(engine->sram, &creq->op_tmpl, sizeof(creq->op_tmpl));
+       if (!sreq->offset) {
+               digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
+               for (i = 0; i < digsize / 4; i++)
+                       writel_relaxed(creq->state[i], engine->regs + CESA_IVDIG(i));
+       }
 
        if (creq->cache_ptr)
                memcpy_toio(engine->sram + CESA_SA_DATA_SRAM_OFFSET,
index daadd20aa936a85e087ba0145147ffa48eac05a9..3e2ab3b14eea205f19e8b436291e5117cec9567d 100644 (file)
@@ -14,7 +14,7 @@ if DEV_DAX
 
 config DEV_DAX_PMEM
        tristate "PMEM DAX: direct access to persistent memory"
-       depends on NVDIMM_DAX
+       depends on LIBNVDIMM && NVDIMM_DAX
        default DEV_DAX
        help
          Support raw access to persistent memory.  Note that this
index 0e499bfca41ccda4752463f770dd495259fb255e..286447a83dab809e0522e461c7e6ca416e997462 100644 (file)
@@ -270,8 +270,8 @@ static int check_vma(struct dax_dev *dax_dev, struct vm_area_struct *vma,
        if (!dax_dev->alive)
                return -ENXIO;
 
-       /* prevent private / writable mappings from being established */
-       if ((vma->vm_flags & (VM_NORESERVE|VM_SHARED|VM_WRITE)) == VM_WRITE) {
+       /* prevent private mappings from being established */
+       if ((vma->vm_flags & VM_MAYSHARE) != VM_MAYSHARE) {
                dev_info(dev, "%s: %s: fail, attempted private mapping\n",
                                current->comm, func);
                return -EINVAL;
index 9630d8837ba94ed3badc9a3755b53c08123b9a51..73c6ce93a0d9204227818465a707db9f7d5806fb 100644 (file)
@@ -44,7 +44,6 @@ static void dax_pmem_percpu_exit(void *data)
 
        dev_dbg(dax_pmem->dev, "%s\n", __func__);
        percpu_ref_exit(ref);
-       wait_for_completion(&dax_pmem->cmp);
 }
 
 static void dax_pmem_percpu_kill(void *data)
@@ -54,6 +53,7 @@ static void dax_pmem_percpu_kill(void *data)
 
        dev_dbg(dax_pmem->dev, "%s\n", __func__);
        percpu_ref_kill(ref);
+       wait_for_completion(&dax_pmem->cmp);
 }
 
 static int dax_pmem_probe(struct device *dev)
@@ -78,7 +78,9 @@ static int dax_pmem_probe(struct device *dev)
        nsio = to_nd_namespace_io(&ndns->dev);
 
        /* parse the 'pfn' info block via ->rw_bytes */
-       devm_nsio_enable(dev, nsio);
+       rc = devm_nsio_enable(dev, nsio);
+       if (rc)
+               return rc;
        altmap = nvdimm_setup_pfn(nd_pfn, &res, &__altmap);
        if (IS_ERR(altmap))
                return PTR_ERR(altmap);
index af63a6bcf564a53574eba818a9e6c2cd07ff9faa..141aefbe37ec93d1f4f38d1be5e2cf8d93266725 100644 (file)
@@ -306,6 +306,7 @@ config MMP_TDMA
        depends on ARCH_MMP || COMPILE_TEST
        select DMA_ENGINE
        select MMP_SRAM if ARCH_MMP
+       select GENERIC_ALLOCATOR
        help
          Support the MMP Two-Channel DMA engine.
          This engine used for MMP Audio DMA and pxa910 SQU.
index bac5f023013b23c92519f052f8523b6008524271..d5ba43a87a682b6e718d5e2ad7c804498bad61de 100644 (file)
@@ -317,6 +317,12 @@ static irqreturn_t cppi41_irq(int irq, void *data)
 
                while (val) {
                        u32 desc, len;
+                       int error;
+
+                       error = pm_runtime_get(cdd->ddev.dev);
+                       if (error < 0)
+                               dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n",
+                                       __func__, error);
 
                        q_num = __fls(val);
                        val &= ~(1 << q_num);
@@ -338,7 +344,6 @@ static irqreturn_t cppi41_irq(int irq, void *data)
                        dma_cookie_complete(&c->txd);
                        dmaengine_desc_get_callback_invoke(&c->txd, NULL);
 
-                       /* Paired with cppi41_dma_issue_pending */
                        pm_runtime_mark_last_busy(cdd->ddev.dev);
                        pm_runtime_put_autosuspend(cdd->ddev.dev);
                }
@@ -362,8 +367,13 @@ static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
        int error;
 
        error = pm_runtime_get_sync(cdd->ddev.dev);
-       if (error < 0)
+       if (error < 0) {
+               dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n",
+                       __func__, error);
+               pm_runtime_put_noidle(cdd->ddev.dev);
+
                return error;
+       }
 
        dma_cookie_init(chan);
        dma_async_tx_descriptor_init(&c->txd, chan);
@@ -385,8 +395,11 @@ static void cppi41_dma_free_chan_resources(struct dma_chan *chan)
        int error;
 
        error = pm_runtime_get_sync(cdd->ddev.dev);
-       if (error < 0)
+       if (error < 0) {
+               pm_runtime_put_noidle(cdd->ddev.dev);
+
                return;
+       }
 
        WARN_ON(!list_empty(&cdd->pending));
 
@@ -460,9 +473,9 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan)
        struct cppi41_dd *cdd = c->cdd;
        int error;
 
-       /* PM runtime paired with dmaengine_desc_get_callback_invoke */
        error = pm_runtime_get(cdd->ddev.dev);
        if ((error != -EINPROGRESS) && error < 0) {
+               pm_runtime_put_noidle(cdd->ddev.dev);
                dev_err(cdd->ddev.dev, "Failed to pm_runtime_get: %i\n",
                        error);
 
@@ -473,6 +486,9 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan)
                push_desc_queue(c);
        else
                pending_desc(c);
+
+       pm_runtime_mark_last_busy(cdd->ddev.dev);
+       pm_runtime_put_autosuspend(cdd->ddev.dev);
 }
 
 static u32 get_host_pd0(u32 length)
@@ -1059,8 +1075,8 @@ err_chans:
        deinit_cppi41(dev, cdd);
 err_init_cppi:
        pm_runtime_dont_use_autosuspend(dev);
-       pm_runtime_put_sync(dev);
 err_get_sync:
+       pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
        iounmap(cdd->usbss_mem);
        iounmap(cdd->ctrl_mem);
@@ -1072,7 +1088,12 @@ err_get_sync:
 static int cppi41_dma_remove(struct platform_device *pdev)
 {
        struct cppi41_dd *cdd = platform_get_drvdata(pdev);
+       int error;
 
+       error = pm_runtime_get_sync(&pdev->dev);
+       if (error < 0)
+               dev_err(&pdev->dev, "%s could not pm_runtime_get: %i\n",
+                       __func__, error);
        of_dma_controller_free(pdev->dev.of_node);
        dma_async_device_unregister(&cdd->ddev);
 
index e18a58068bca75862bfcaee08952575925d284a7..77242b37ef87866acf4681c0934c906ecb75de77 100644 (file)
@@ -1628,6 +1628,7 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
        if (echan->slot[0] < 0) {
                dev_err(dev, "Entry slot allocation failed for channel %u\n",
                        EDMA_CHAN_SLOT(echan->ch_num));
+               ret = echan->slot[0];
                goto err_slot;
        }
 
index 83461994e4181a67b73c5ceaa7bfb24bada1f9d5..a2358780ab2c3ca6ea52c834fa692a644e35c0cb 100644 (file)
@@ -578,7 +578,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
 
        burst = convert_burst(8);
        width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
-       v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
+       v_lli->cfg = DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
                DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
                DMA_CHAN_CFG_DST_LINEAR_MODE |
                DMA_CHAN_CFG_SRC_LINEAR_MODE |
index 56e6c4c7c60d265912a2c2990170a48b616f9bef..d836d4ce5ee46ab9da23715881d0cdd82ec7fcb5 100644 (file)
@@ -274,9 +274,10 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
        struct arizona *arizona = info->arizona;
        const char *widget = arizona_extcon_get_micbias(info);
        struct snd_soc_dapm_context *dapm = arizona->dapm;
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        int ret;
 
-       ret = snd_soc_dapm_force_enable_pin(dapm, widget);
+       ret = snd_soc_component_force_enable_pin(component, widget);
        if (ret != 0)
                dev_warn(arizona->dev, "Failed to enable %s: %d\n",
                         widget, ret);
@@ -284,7 +285,7 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
        snd_soc_dapm_sync(dapm);
 
        if (!arizona->pdata.micd_force_micbias) {
-               ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
+               ret = snd_soc_component_disable_pin(component, widget);
                if (ret != 0)
                        dev_warn(arizona->dev, "Failed to disable %s: %d\n",
                                 widget, ret);
@@ -349,6 +350,7 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
        struct arizona *arizona = info->arizona;
        const char *widget = arizona_extcon_get_micbias(info);
        struct snd_soc_dapm_context *dapm = arizona->dapm;
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        bool change;
        int ret;
 
@@ -356,7 +358,7 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
                                 ARIZONA_MICD_ENA, 0,
                                 &change);
 
-       ret = snd_soc_dapm_disable_pin(dapm, widget);
+       ret = snd_soc_component_disable_pin(component, widget);
        if (ret != 0)
                dev_warn(arizona->dev,
                         "Failed to disable %s: %d\n",
index ca957a5f4291228a77c85b65cf08f0fb690bf522..b8cde096a808f552fde97e0cb85c101ab4139881 100644 (file)
@@ -51,7 +51,7 @@ static void qcom_usb_extcon_detect_cable(struct work_struct *work)
        if (ret)
                return;
 
-       extcon_set_state(info->edev, EXTCON_USB_HOST, !id);
+       extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !id);
 }
 
 static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id)
index 309311b1faae18752a9bf24b0d350933aad4627c..15475892af0c948c12f0f5c9ba6375c1f51bdcbf 100644 (file)
@@ -73,13 +73,13 @@ struct rfc2734_header {
 
 #define fwnet_get_hdr_lf(h)            (((h)->w0 & 0xc0000000) >> 30)
 #define fwnet_get_hdr_ether_type(h)    (((h)->w0 & 0x0000ffff))
-#define fwnet_get_hdr_dg_size(h)       (((h)->w0 & 0x0fff0000) >> 16)
+#define fwnet_get_hdr_dg_size(h)       ((((h)->w0 & 0x0fff0000) >> 16) + 1)
 #define fwnet_get_hdr_fg_off(h)                (((h)->w0 & 0x00000fff))
 #define fwnet_get_hdr_dgl(h)           (((h)->w1 & 0xffff0000) >> 16)
 
-#define fwnet_set_hdr_lf(lf)           ((lf)  << 30)
+#define fwnet_set_hdr_lf(lf)           ((lf) << 30)
 #define fwnet_set_hdr_ether_type(et)   (et)
-#define fwnet_set_hdr_dg_size(dgs)     ((dgs) << 16)
+#define fwnet_set_hdr_dg_size(dgs)     (((dgs) - 1) << 16)
 #define fwnet_set_hdr_fg_off(fgo)      (fgo)
 
 #define fwnet_set_hdr_dgl(dgl)         ((dgl) << 16)
@@ -578,6 +578,9 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
        int retval;
        u16 ether_type;
 
+       if (len <= RFC2374_UNFRAG_HDR_SIZE)
+               return 0;
+
        hdr.w0 = be32_to_cpu(buf[0]);
        lf = fwnet_get_hdr_lf(&hdr);
        if (lf == RFC2374_HDR_UNFRAG) {
@@ -602,7 +605,12 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
                return fwnet_finish_incoming_packet(net, skb, source_node_id,
                                                    is_broadcast, ether_type);
        }
+
        /* A datagram fragment has been received, now the fun begins. */
+
+       if (len <= RFC2374_FRAG_HDR_SIZE)
+               return 0;
+
        hdr.w1 = ntohl(buf[1]);
        buf += 2;
        len -= RFC2374_FRAG_HDR_SIZE;
@@ -614,7 +622,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
                fg_off = fwnet_get_hdr_fg_off(&hdr);
        }
        datagram_label = fwnet_get_hdr_dgl(&hdr);
-       dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
+       dg_size = fwnet_get_hdr_dg_size(&hdr);
+
+       if (fg_off + len > dg_size)
+               return 0;
 
        spin_lock_irqsave(&dev->lock, flags);
 
@@ -722,6 +733,22 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,
        fw_send_response(card, r, rcode);
 }
 
+static int gasp_source_id(__be32 *p)
+{
+       return be32_to_cpu(p[0]) >> 16;
+}
+
+static u32 gasp_specifier_id(__be32 *p)
+{
+       return (be32_to_cpu(p[0]) & 0xffff) << 8 |
+              (be32_to_cpu(p[1]) & 0xff000000) >> 24;
+}
+
+static u32 gasp_version(__be32 *p)
+{
+       return be32_to_cpu(p[1]) & 0xffffff;
+}
+
 static void fwnet_receive_broadcast(struct fw_iso_context *context,
                u32 cycle, size_t header_length, void *header, void *data)
 {
@@ -731,9 +758,6 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
        __be32 *buf_ptr;
        int retval;
        u32 length;
-       u16 source_node_id;
-       u32 specifier_id;
-       u32 ver;
        unsigned long offset;
        unsigned long flags;
 
@@ -750,22 +774,17 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       specifier_id =    (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8
-                       | (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24;
-       ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
-       source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
-
-       if (specifier_id == IANA_SPECIFIER_ID &&
-           (ver == RFC2734_SW_VERSION
+       if (length > IEEE1394_GASP_HDR_SIZE &&
+           gasp_specifier_id(buf_ptr) == IANA_SPECIFIER_ID &&
+           (gasp_version(buf_ptr) == RFC2734_SW_VERSION
 #if IS_ENABLED(CONFIG_IPV6)
-            || ver == RFC3146_SW_VERSION
+            || gasp_version(buf_ptr) == RFC3146_SW_VERSION
 #endif
-           )) {
-               buf_ptr += 2;
-               length -= IEEE1394_GASP_HDR_SIZE;
-               fwnet_incoming_packet(dev, buf_ptr, length, source_node_id,
+           ))
+               fwnet_incoming_packet(dev, buf_ptr + 2,
+                                     length - IEEE1394_GASP_HDR_SIZE,
+                                     gasp_source_id(buf_ptr),
                                      context->card->generation, true);
-       }
 
        packet.payload_length = dev->rcv_buffer_size;
        packet.interrupt = 1;
index 631c977b0da5f817b7ecf950d94f90198a53abbe..180f0a96528cee063d3da64fa620d6de0eebdfcf 100644 (file)
@@ -566,6 +566,11 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
 
        lynx->registers = ioremap_nocache(pci_resource_start(dev, 0),
                                          PCILYNX_MAX_REGISTER);
+       if (lynx->registers == NULL) {
+               dev_err(&dev->dev, "Failed to map registers\n");
+               ret = -ENOMEM;
+               goto fail_deallocate_lynx;
+       }
 
        lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device,
                                sizeof(struct pcl), &lynx->rcv_start_pcl_bus);
@@ -578,7 +583,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
            lynx->rcv_buffer == NULL) {
                dev_err(&dev->dev, "Failed to allocate receive buffer\n");
                ret = -ENOMEM;
-               goto fail_deallocate;
+               goto fail_deallocate_buffers;
        }
        lynx->rcv_start_pcl->next       = cpu_to_le32(lynx->rcv_pcl_bus);
        lynx->rcv_pcl->next             = cpu_to_le32(PCL_NEXT_INVALID);
@@ -641,7 +646,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
                dev_err(&dev->dev,
                        "Failed to allocate shared interrupt %d\n", dev->irq);
                ret = -EIO;
-               goto fail_deallocate;
+               goto fail_deallocate_buffers;
        }
 
        lynx->misc.parent = &dev->dev;
@@ -668,7 +673,7 @@ fail_free_irq:
        reg_write(lynx, PCI_INT_ENABLE, 0);
        free_irq(lynx->pci_device->irq, lynx);
 
-fail_deallocate:
+fail_deallocate_buffers:
        if (lynx->rcv_start_pcl)
                pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
                                lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
@@ -679,6 +684,8 @@ fail_deallocate:
                pci_free_consistent(lynx->pci_device, PAGE_SIZE,
                                lynx->rcv_buffer, lynx->rcv_buffer_bus);
        iounmap(lynx->registers);
+
+fail_deallocate_lynx:
        kfree(lynx);
 
 fail_disable:
index c06945160a4154a5f8d518192b7adb16c4ab325d..5e23e2d305e71db52a7f9e27a63ce760f4c752fd 100644 (file)
@@ -11,7 +11,7 @@ cflags-$(CONFIG_X86)          += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
                                   -mno-mmx -mno-sse
 
 cflags-$(CONFIG_ARM64)         := $(subst -pg,,$(KBUILD_CFLAGS))
-cflags-$(CONFIG_ARM)           := $(subst -pg,,$(KBUILD_CFLAGS)) \
+cflags-$(CONFIG_ARM)           := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \
                                   -fno-builtin -fpic -mno-single-pic-base
 
 cflags-$(CONFIG_EFI_ARMSTUB)   += -I$(srctree)/scripts/dtc/libfdt
@@ -79,5 +79,6 @@ quiet_cmd_stubcopy = STUBCPY $@
 # decompressor. So move our .data to .data.efistub, which is preserved
 # explicitly by the decompressor linker script.
 #
-STUBCOPY_FLAGS-$(CONFIG_ARM)   += --rename-section .data=.data.efistub
+STUBCOPY_FLAGS-$(CONFIG_ARM)   += --rename-section .data=.data.efistub \
+                                  -R ___ksymtab+sort -R ___kcrctab+sort
 STUBCOPY_RELOC-$(CONFIG_ARM)   := R_ARM_ABS
index 26ee00f6bd5829c04d66b4621643375959c161da..ed37e5908b910cd51cb378ffc171fe2a9104c082 100644 (file)
@@ -22,10 +22,6 @@ menuconfig GPIOLIB
 
 if GPIOLIB
 
-config GPIO_DEVRES
-       def_bool y
-       depends on HAS_IOMEM
-
 config OF_GPIO
        def_bool y
        depends on OF
@@ -284,7 +280,7 @@ config GPIO_MM_LANTIQ
 
 config GPIO_MOCKUP
        tristate "GPIO Testing Driver"
-       depends on GPIOLIB
+       depends on GPIOLIB && SYSFS
        select GPIO_SYSFS
        help
          This enables GPIO Testing driver, which provides a way to test GPIO
index ab28a2daeacc92fb1dcd648bbecb09c0b2ce8fc4..d074c2299393dc9cef3456b0068ff2d229677c27 100644 (file)
@@ -2,7 +2,7 @@
 
 ccflags-$(CONFIG_DEBUG_GPIO)   += -DDEBUG
 
-obj-$(CONFIG_GPIO_DEVRES)      += devres.o
+obj-$(CONFIG_GPIOLIB)          += devres.o
 obj-$(CONFIG_GPIOLIB)          += gpiolib.o
 obj-$(CONFIG_GPIOLIB)          += gpiolib-legacy.o
 obj-$(CONFIG_OF_GPIO)          += gpiolib-of.o
index 9457e2022bf6c1e0c4f8cc4cd11acf224ff68e54..dc37dbe4b46d8889bfaddeac0c492dd6ed56090c 100644 (file)
@@ -219,6 +219,7 @@ static const struct of_device_id ath79_gpio_of_match[] = {
        { .compatible = "qca,ar9340-gpio" },
        {},
 };
+MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
 
 static int ath79_gpio_probe(struct platform_device *pdev)
 {
index 425501c39527038509a0c3af752598d0c53ee049..793518a30afe6c97a97bfe5db1d62cb1651077c1 100644 (file)
@@ -239,7 +239,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
                                irq_hw_number_t hwirq)
 {
        irq_set_chip_data(irq, h->host_data);
-       irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq);
+       irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_edge_irq);
 
        return 0;
 }
index cd5dc27320a273ab52bc119f57f2f87f9cf240b2..1ed6132b993c6fbcf28997c4327572011c054930 100644 (file)
@@ -293,10 +293,10 @@ static void mvebu_gpio_irq_ack(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct mvebu_gpio_chip *mvchip = gc->private;
-       u32 mask = ~(1 << (d->irq - gc->irq_base));
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       writel_relaxed(mask, mvebu_gpioreg_edge_cause(mvchip));
+       writel_relaxed(~mask, mvebu_gpioreg_edge_cause(mvchip));
        irq_gc_unlock(gc);
 }
 
@@ -305,7 +305,7 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct mvebu_gpio_chip *mvchip = gc->private;
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
        ct->mask_cache_priv &= ~mask;
@@ -319,8 +319,7 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct mvebu_gpio_chip *mvchip = gc->private;
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
-
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
        ct->mask_cache_priv |= mask;
@@ -333,8 +332,7 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d)
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct mvebu_gpio_chip *mvchip = gc->private;
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
-
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
        ct->mask_cache_priv &= ~mask;
@@ -347,8 +345,7 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct mvebu_gpio_chip *mvchip = gc->private;
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
-
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
        ct->mask_cache_priv |= mask;
@@ -462,7 +459,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
        for (i = 0; i < mvchip->chip.ngpio; i++) {
                int irq;
 
-               irq = mvchip->irqbase + i;
+               irq = irq_find_mapping(mvchip->domain, i);
 
                if (!(cause & (1 << i)))
                        continue;
@@ -655,6 +652,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        struct irq_chip_type *ct;
        struct clk *clk;
        unsigned int ngpios;
+       bool have_irqs;
        int soc_variant;
        int i, cpu, id;
        int err;
@@ -665,6 +663,9 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        else
                soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
 
+       /* Some gpio controllers do not provide irq support */
+       have_irqs = of_irq_count(np) != 0;
+
        mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip),
                              GFP_KERNEL);
        if (!mvchip)
@@ -697,7 +698,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        mvchip->chip.get = mvebu_gpio_get;
        mvchip->chip.direction_output = mvebu_gpio_direction_output;
        mvchip->chip.set = mvebu_gpio_set;
-       mvchip->chip.to_irq = mvebu_gpio_to_irq;
+       if (have_irqs)
+               mvchip->chip.to_irq = mvebu_gpio_to_irq;
        mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
        mvchip->chip.ngpio = ngpios;
        mvchip->chip.can_sleep = false;
@@ -758,34 +760,30 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);
 
        /* Some gpio controllers do not provide irq support */
-       if (!of_irq_count(np))
+       if (!have_irqs)
                return 0;
 
-       /* Setup the interrupt handlers. Each chip can have up to 4
-        * interrupt handlers, with each handler dealing with 8 GPIO
-        * pins. */
-       for (i = 0; i < 4; i++) {
-               int irq = platform_get_irq(pdev, i);
-
-               if (irq < 0)
-                       continue;
-               irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
-                                                mvchip);
-       }
-
-       mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1);
-       if (mvchip->irqbase < 0) {
-               dev_err(&pdev->dev, "no irqs\n");
-               return mvchip->irqbase;
+       mvchip->domain =
+           irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL);
+       if (!mvchip->domain) {
+               dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
+                       mvchip->chip.label);
+               return -ENODEV;
        }
 
-       gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase,
-                                   mvchip->membase, handle_level_irq);
-       if (!gc) {
-               dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n");
-               return -ENOMEM;
+       err = irq_alloc_domain_generic_chips(
+           mvchip->domain, ngpios, 2, np->name, handle_level_irq,
+           IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
+       if (err) {
+               dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
+                       mvchip->chip.label);
+               goto err_domain;
        }
 
+       /* NOTE: The common accessors cannot be used because of the percpu
+        * access to the mask registers
+        */
+       gc = irq_get_domain_generic_chip(mvchip->domain, 0);
        gc->private = mvchip;
        ct = &gc->chip_types[0];
        ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
@@ -803,27 +801,23 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        ct->handler = handle_edge_irq;
        ct->chip.name = mvchip->chip.label;
 
-       irq_setup_generic_chip(gc, IRQ_MSK(ngpios), 0,
-                              IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
+       /* Setup the interrupt handlers. Each chip can have up to 4
+        * interrupt handlers, with each handler dealing with 8 GPIO
+        * pins.
+        */
+       for (i = 0; i < 4; i++) {
+               int irq = platform_get_irq(pdev, i);
 
-       /* Setup irq domain on top of the generic chip. */
-       mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
-                                              mvchip->irqbase,
-                                              &irq_domain_simple_ops,
-                                              mvchip);
-       if (!mvchip->domain) {
-               dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
-                       mvchip->chip.label);
-               err = -ENODEV;
-               goto err_generic_chip;
+               if (irq < 0)
+                       continue;
+               irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
+                                                mvchip);
        }
 
        return 0;
 
-err_generic_chip:
-       irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
-                               IRQ_LEVEL | IRQ_NOPROBE);
-       kfree(gc);
+err_domain:
+       irq_domain_remove(mvchip->domain);
 
        return err;
 }
index b9daa0bf32a46375784c2f6ade582ba4c46c4a74..ee1724806f46db13d7eb2b41ce900fd2043b3d91 100644 (file)
@@ -308,8 +308,10 @@ static int mxs_gpio_probe(struct platform_device *pdev)
        writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
 
        irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
-       if (irq_base < 0)
-               return irq_base;
+       if (irq_base < 0) {
+               err = irq_base;
+               goto out_iounmap;
+       }
 
        port->domain = irq_domain_add_legacy(np, 32, irq_base, 0,
                                             &irq_domain_simple_ops, NULL);
@@ -349,6 +351,8 @@ out_irqdomain_remove:
        irq_domain_remove(port->domain);
 out_irqdesc_free:
        irq_free_descs(irq_base, 32);
+out_iounmap:
+       iounmap(port->base);
        return err;
 }
 
index e422568e14ad19273c277fc1565d068ab2819c53..fe731f09425712b546655d7097a84b7a47a35d68 100644 (file)
@@ -372,14 +372,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
 
        bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
 
-       memcpy(reg_val, chip->reg_output, NBANK(chip));
        mutex_lock(&chip->i2c_lock);
+       memcpy(reg_val, chip->reg_output, NBANK(chip));
        for (bank = 0; bank < NBANK(chip); bank++) {
                bank_mask = mask[bank / sizeof(*mask)] >>
                           ((bank % sizeof(*mask)) * 8);
                if (bank_mask) {
                        bank_val = bits[bank / sizeof(*bits)] >>
                                  ((bank % sizeof(*bits)) * 8);
+                       bank_val &= bank_mask;
                        reg_val[bank] = (reg_val[bank] & ~bank_mask) | bank_val;
                }
        }
@@ -607,7 +608,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 
        if (client->irq && irq_base != -1
                        && (chip->driver_data & PCA_INT)) {
-
                ret = pca953x_read_regs(chip,
                                        chip->regs->input, chip->irq_stat);
                if (ret)
index e7d422a6b90bd71427694b8f3efc607d78c254cd..5b0042776ec7081f49d3eaff1dc56fe08733f3d1 100644 (file)
@@ -409,7 +409,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
                 * 801/1801/1600, bits are cleared when read.
                 * Edge detect register is not present on 801/1600/1801
                 */
-               if (stmpe->partnum != STMPE801 || stmpe->partnum != STMPE1600 ||
+               if (stmpe->partnum != STMPE801 && stmpe->partnum != STMPE1600 &&
                    stmpe->partnum != STMPE1801) {
                        stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
                        stmpe_reg_write(stmpe,
index 5a5a6cb00eea9cc7e21666812ed6571fa55ff92d..d6e21f1a70a9dc685aa8dfc786230ad620022691 100644 (file)
@@ -97,7 +97,7 @@ static int tc3589x_gpio_get_direction(struct gpio_chip *chip,
        if (ret < 0)
                return ret;
 
-       return !!(ret & BIT(pos));
+       return !(ret & BIT(pos));
 }
 
 static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip,
index 99256115bea55c12710ae6c19a94c09a8e01d918..c2a80b4cbf32c2ce3b83eedf82339a8ad0177b16 100644 (file)
@@ -66,6 +66,7 @@ static const struct of_device_id ts4800_gpio_of_match[] = {
        { .compatible = "technologic,ts4800-gpio", },
        {},
 };
+MODULE_DEVICE_TABLE(of, ts4800_gpio_of_match);
 
 static struct platform_driver ts4800_gpio_driver = {
        .driver = {
index 58ece201b8e62328741a1f62a1fbb33dfedbf996..72a4b326fd0da2f1d84f9e05a97416ff5761c9d3 100644 (file)
@@ -653,14 +653,17 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
 {
        int idx, i;
        unsigned int irq_flags;
+       int ret = -ENOENT;
 
        for (i = 0, idx = 0; idx <= index; i++) {
                struct acpi_gpio_info info;
                struct gpio_desc *desc;
 
                desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
-               if (IS_ERR(desc))
+               if (IS_ERR(desc)) {
+                       ret = PTR_ERR(desc);
                        break;
+               }
                if (info.gpioint && idx++ == index) {
                        int irq = gpiod_to_irq(desc);
 
@@ -679,7 +682,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
                }
 
        }
-       return -ENOENT;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
 
index ecad3f0e3b772772440bcae1735c3430a71f030d..193f15d50bbaa33e9728f98c462f8fddaf96971b 100644 (file)
 
 #include "gpiolib.h"
 
-static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
+static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
 {
-       return chip->gpiodev->dev.of_node == data;
+       struct of_phandle_args *gpiospec = data;
+
+       return chip->gpiodev->dev.of_node == gpiospec->np &&
+                               chip->of_xlate(chip, gpiospec, NULL) >= 0;
 }
 
-static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
+static struct gpio_chip *of_find_gpiochip_by_xlate(
+                                       struct of_phandle_args *gpiospec)
 {
-       return gpiochip_find(np, of_gpiochip_match_node);
+       return gpiochip_find(gpiospec, of_gpiochip_match_node_and_xlate);
 }
 
 static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
@@ -79,7 +83,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
                return ERR_PTR(ret);
        }
 
-       chip = of_find_gpiochip_by_node(gpiospec.np);
+       chip = of_find_gpiochip_by_xlate(&gpiospec);
        if (!chip) {
                desc = ERR_PTR(-EPROBE_DEFER);
                goto out;
index f0fc3a0d37c829de62e3c136f37cdb7a835a11b7..868128a676bae832090c2c18b1f45e94c2996a5f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/uaccess.h>
 #include <linux/compat.h>
 #include <linux/anon_inodes.h>
+#include <linux/file.h>
 #include <linux/kfifo.h>
 #include <linux/poll.h>
 #include <linux/timekeeping.h>
@@ -333,6 +334,13 @@ struct linehandle_state {
        u32 numdescs;
 };
 
+#define GPIOHANDLE_REQUEST_VALID_FLAGS \
+       (GPIOHANDLE_REQUEST_INPUT | \
+       GPIOHANDLE_REQUEST_OUTPUT | \
+       GPIOHANDLE_REQUEST_ACTIVE_LOW | \
+       GPIOHANDLE_REQUEST_OPEN_DRAIN | \
+       GPIOHANDLE_REQUEST_OPEN_SOURCE)
+
 static long linehandle_ioctl(struct file *filep, unsigned int cmd,
                             unsigned long arg)
 {
@@ -344,6 +352,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
        if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
                int val;
 
+               memset(&ghd, 0, sizeof(ghd));
+
                /* TODO: check if descriptors are really input */
                for (i = 0; i < lh->numdescs; i++) {
                        val = gpiod_get_value_cansleep(lh->descs[i]);
@@ -414,6 +424,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
 {
        struct gpiohandle_request handlereq;
        struct linehandle_state *lh;
+       struct file *file;
        int fd, i, ret;
 
        if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
@@ -444,6 +455,17 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
                u32 lflags = handlereq.flags;
                struct gpio_desc *desc;
 
+               if (offset >= gdev->ngpio) {
+                       ret = -EINVAL;
+                       goto out_free_descs;
+               }
+
+               /* Return an error if a unknown flag is set */
+               if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) {
+                       ret = -EINVAL;
+                       goto out_free_descs;
+               }
+
                desc = &gdev->descs[offset];
                ret = gpiod_request(desc, lh->label);
                if (ret)
@@ -479,26 +501,41 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
        i--;
        lh->numdescs = handlereq.lines;
 
-       fd = anon_inode_getfd("gpio-linehandle",
-                             &linehandle_fileops,
-                             lh,
-                             O_RDONLY | O_CLOEXEC);
+       fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
                ret = fd;
                goto out_free_descs;
        }
 
+       file = anon_inode_getfile("gpio-linehandle",
+                                 &linehandle_fileops,
+                                 lh,
+                                 O_RDONLY | O_CLOEXEC);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto out_put_unused_fd;
+       }
+
        handlereq.fd = fd;
        if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
-               ret = -EFAULT;
-               goto out_free_descs;
+               /*
+                * fput() will trigger the release() callback, so do not go onto
+                * the regular error cleanup path here.
+                */
+               fput(file);
+               put_unused_fd(fd);
+               return -EFAULT;
        }
 
+       fd_install(fd, file);
+
        dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
                lh->numdescs);
 
        return 0;
 
+out_put_unused_fd:
+       put_unused_fd(fd);
 out_free_descs:
        for (; i >= 0; i--)
                gpiod_free(lh->descs[i]);
@@ -536,6 +573,10 @@ struct lineevent_state {
        struct mutex read_lock;
 };
 
+#define GPIOEVENT_REQUEST_VALID_FLAGS \
+       (GPIOEVENT_REQUEST_RISING_EDGE | \
+       GPIOEVENT_REQUEST_FALLING_EDGE)
+
 static unsigned int lineevent_poll(struct file *filep,
                                   struct poll_table_struct *wait)
 {
@@ -623,6 +664,8 @@ static long lineevent_ioctl(struct file *filep, unsigned int cmd,
        if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
                int val;
 
+               memset(&ghd, 0, sizeof(ghd));
+
                val = gpiod_get_value_cansleep(le->desc);
                if (val < 0)
                        return val;
@@ -695,6 +738,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        struct gpioevent_request eventreq;
        struct lineevent_state *le;
        struct gpio_desc *desc;
+       struct file *file;
        u32 offset;
        u32 lflags;
        u32 eflags;
@@ -726,6 +770,18 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        lflags = eventreq.handleflags;
        eflags = eventreq.eventflags;
 
+       if (offset >= gdev->ngpio) {
+               ret = -EINVAL;
+               goto out_free_label;
+       }
+
+       /* Return an error if a unknown flag is set */
+       if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
+           (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) {
+               ret = -EINVAL;
+               goto out_free_label;
+       }
+
        /* This is just wrong: we don't look for events on output lines */
        if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
                ret = -EINVAL;
@@ -777,23 +833,38 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        if (ret)
                goto out_free_desc;
 
-       fd = anon_inode_getfd("gpio-event",
-                             &lineevent_fileops,
-                             le,
-                             O_RDONLY | O_CLOEXEC);
+       fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
                ret = fd;
                goto out_free_irq;
        }
 
+       file = anon_inode_getfile("gpio-event",
+                                 &lineevent_fileops,
+                                 le,
+                                 O_RDONLY | O_CLOEXEC);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto out_put_unused_fd;
+       }
+
        eventreq.fd = fd;
        if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
-               ret = -EFAULT;
-               goto out_free_irq;
+               /*
+                * fput() will trigger the release() callback, so do not go onto
+                * the regular error cleanup path here.
+                */
+               fput(file);
+               put_unused_fd(fd);
+               return -EFAULT;
        }
 
+       fd_install(fd, file);
+
        return 0;
 
+out_put_unused_fd:
+       put_unused_fd(fd);
 out_free_irq:
        free_irq(le->irq, le);
 out_free_desc:
@@ -823,6 +894,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
                struct gpiochip_info chipinfo;
 
+               memset(&chipinfo, 0, sizeof(chipinfo));
+
                strncpy(chipinfo.name, dev_name(&gdev->dev),
                        sizeof(chipinfo.name));
                chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
@@ -839,7 +912,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
                if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
                        return -EFAULT;
-               if (lineinfo.line_offset > gdev->ngpio)
+               if (lineinfo.line_offset >= gdev->ngpio)
                        return -EINVAL;
 
                desc = &gdev->descs[lineinfo.line_offset];
@@ -2664,8 +2737,11 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
        if (IS_ERR(desc))
                return PTR_ERR(desc);
 
-       /* Flush direction if something changed behind our back */
-       if (chip->get_direction) {
+       /*
+        * If it's fast: flush the direction setting if something changed
+        * behind our back
+        */
+       if (!chip->can_sleep && chip->get_direction) {
                int dir = chip->get_direction(chip, offset);
 
                if (dir)
index 039b57e4644c3936bfe345426ff17754847b199b..05c2850c04b00f01bfcda21182fdaa15f3c0edb1 100644 (file)
@@ -459,6 +459,7 @@ struct amdgpu_bo {
        u64                             metadata_flags;
        void                            *metadata;
        u32                             metadata_size;
+       unsigned                        prime_shared_count;
        /* list of all virtual address to which this bo
         * is associated to
         */
@@ -2471,6 +2472,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
                                 struct drm_file *file_priv);
 void amdgpu_driver_preclose_kms(struct drm_device *dev,
                                struct drm_file *file_priv);
+int amdgpu_suspend(struct amdgpu_device *adev);
 int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon);
 int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon);
 u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe);
index 892d60fb225b56b25d7a44edec959ab56f45ed90..2057683f7b5998d3641cf20af336838ee72d27d2 100644 (file)
@@ -395,9 +395,12 @@ static int acp_hw_fini(void *handle)
 {
        int i, ret;
        struct device *dev;
-
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       /* return early if no ACP */
+       if (!adev->acp.acp_genpd)
+               return 0;
+
        for (i = 0; i < ACP_DEVS ; i++) {
                dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i);
                ret = pm_genpd_remove_device(&adev->acp.acp_genpd->gpd, dev);
index dae35a96a694d0b6ffc3de5aae94e7344a69e565..6c343a9331825452a572a876649dc3b67eba28c4 100644 (file)
@@ -34,6 +34,7 @@ struct amdgpu_atpx {
 
 static struct amdgpu_atpx_priv {
        bool atpx_detected;
+       bool bridge_pm_usable;
        /* handle for device - and atpx */
        acpi_handle dhandle;
        acpi_handle other_handle;
@@ -205,7 +206,11 @@ static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx)
        atpx->is_hybrid = false;
        if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) {
                printk("ATPX Hybrid Graphics\n");
-               atpx->functions.power_cntl = false;
+               /*
+                * Disable legacy PM methods only when pcie port PM is usable,
+                * otherwise the device might fail to power off or power on.
+                */
+               atpx->functions.power_cntl = !amdgpu_atpx_priv.bridge_pm_usable;
                atpx->is_hybrid = true;
        }
 
@@ -555,17 +560,25 @@ static bool amdgpu_atpx_detect(void)
        struct pci_dev *pdev = NULL;
        bool has_atpx = false;
        int vga_count = 0;
+       bool d3_supported = false;
+       struct pci_dev *parent_pdev;
 
        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
                vga_count++;
 
                has_atpx |= (amdgpu_atpx_pci_probe_handle(pdev) == true);
+
+               parent_pdev = pci_upstream_bridge(pdev);
+               d3_supported |= parent_pdev && parent_pdev->bridge_d3;
        }
 
        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
                vga_count++;
 
                has_atpx |= (amdgpu_atpx_pci_probe_handle(pdev) == true);
+
+               parent_pdev = pci_upstream_bridge(pdev);
+               d3_supported |= parent_pdev && parent_pdev->bridge_d3;
        }
 
        if (has_atpx && vga_count == 2) {
@@ -573,6 +586,7 @@ static bool amdgpu_atpx_detect(void)
                printk(KERN_INFO "vga_switcheroo: detected switching method %s handle\n",
                       acpi_method_name);
                amdgpu_atpx_priv.atpx_detected = true;
+               amdgpu_atpx_priv.bridge_pm_usable = d3_supported;
                amdgpu_atpx_init();
                return true;
        }
index 651115dcce12c6ff332eac87de6e9e5712b6d69c..c02db01f6583e620d885542f37a0da6f1780152e 100644 (file)
@@ -132,7 +132,7 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev,
                entry->priority = min(info[i].bo_priority,
                                      AMDGPU_BO_LIST_MAX_PRIORITY);
                entry->tv.bo = &entry->robj->tbo;
-               entry->tv.shared = true;
+               entry->tv.shared = !entry->robj->prime_shared_count;
 
                if (entry->robj->prefered_domains == AMDGPU_GEM_DOMAIN_GDS)
                        gds_obj = entry->robj;
index 7a8bfa34682fdd8a92959d43328a7de058b42b7f..662976292535856d57dde4788364c20f7fba38e5 100644 (file)
@@ -795,10 +795,19 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
                if (!adev->pm.fw) {
                        switch (adev->asic_type) {
                        case CHIP_TOPAZ:
-                               strcpy(fw_name, "amdgpu/topaz_smc.bin");
+                               if (((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0x81)) ||
+                                   ((adev->pdev->device == 0x6900) && (adev->pdev->revision == 0x83)) ||
+                                   ((adev->pdev->device == 0x6907) && (adev->pdev->revision == 0x87)))
+                                       strcpy(fw_name, "amdgpu/topaz_k_smc.bin");
+                               else
+                                       strcpy(fw_name, "amdgpu/topaz_smc.bin");
                                break;
                        case CHIP_TONGA:
-                               strcpy(fw_name, "amdgpu/tonga_smc.bin");
+                               if (((adev->pdev->device == 0x6939) && (adev->pdev->revision == 0xf1)) ||
+                                   ((adev->pdev->device == 0x6938) && (adev->pdev->revision == 0xf1)))
+                                       strcpy(fw_name, "amdgpu/tonga_k_smc.bin");
+                               else
+                                       strcpy(fw_name, "amdgpu/tonga_smc.bin");
                                break;
                        case CHIP_FIJI:
                                strcpy(fw_name, "amdgpu/fiji_smc.bin");
index 2e3a0543760d0967164b2a5833cf9c39a63bf90b..086aa5c9c6348c45888d0b732f9417c0ec964cbe 100644 (file)
@@ -765,14 +765,20 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
        return ret;
 }
 
-static void amdgpu_connector_destroy(struct drm_connector *connector)
+static void amdgpu_connector_unregister(struct drm_connector *connector)
 {
        struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-       if (amdgpu_connector->ddc_bus->has_aux) {
+       if (amdgpu_connector->ddc_bus && amdgpu_connector->ddc_bus->has_aux) {
                drm_dp_aux_unregister(&amdgpu_connector->ddc_bus->aux);
                amdgpu_connector->ddc_bus->has_aux = false;
        }
+}
+
+static void amdgpu_connector_destroy(struct drm_connector *connector)
+{
+       struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
        amdgpu_connector_free_edid(connector);
        kfree(amdgpu_connector->con_priv);
        drm_connector_unregister(connector);
@@ -826,6 +832,7 @@ static const struct drm_connector_funcs amdgpu_connector_lvds_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = amdgpu_connector_lvds_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .early_unregister = amdgpu_connector_unregister,
        .destroy = amdgpu_connector_destroy,
        .set_property = amdgpu_connector_set_lcd_property,
 };
@@ -936,6 +943,7 @@ static const struct drm_connector_funcs amdgpu_connector_vga_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = amdgpu_connector_vga_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .early_unregister = amdgpu_connector_unregister,
        .destroy = amdgpu_connector_destroy,
        .set_property = amdgpu_connector_set_property,
 };
@@ -1203,6 +1211,7 @@ static const struct drm_connector_funcs amdgpu_connector_dvi_funcs = {
        .detect = amdgpu_connector_dvi_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = amdgpu_connector_set_property,
+       .early_unregister = amdgpu_connector_unregister,
        .destroy = amdgpu_connector_destroy,
        .force = amdgpu_connector_dvi_force,
 };
@@ -1493,6 +1502,7 @@ static const struct drm_connector_funcs amdgpu_connector_dp_funcs = {
        .detect = amdgpu_connector_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = amdgpu_connector_set_property,
+       .early_unregister = amdgpu_connector_unregister,
        .destroy = amdgpu_connector_destroy,
        .force = amdgpu_connector_dvi_force,
 };
@@ -1502,6 +1512,7 @@ static const struct drm_connector_funcs amdgpu_connector_edp_funcs = {
        .detect = amdgpu_connector_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = amdgpu_connector_set_lcd_property,
+       .early_unregister = amdgpu_connector_unregister,
        .destroy = amdgpu_connector_destroy,
        .force = amdgpu_connector_dvi_force,
 };
index b0f6e6957536a7827acc979856f3ef5280b3ce79..82dc8d20e28acfdd2c2c4c2e9dca8ea0cca88d53 100644 (file)
@@ -519,7 +519,8 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
                r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true,
                                           &duplicates);
                if (unlikely(r != 0)) {
-                       DRM_ERROR("ttm_eu_reserve_buffers failed.\n");
+                       if (r != -ERESTARTSYS)
+                               DRM_ERROR("ttm_eu_reserve_buffers failed.\n");
                        goto error_free_pages;
                }
 
index e203e5561107146badbb45a2260763c87e06f8e0..a5e2fcbef0f0f24f54bcf54164eb610c463edd49 100644 (file)
@@ -43,6 +43,9 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, struct amdgpu_ctx *ctx)
                ctx->rings[i].sequence = 1;
                ctx->rings[i].fences = &ctx->fences[amdgpu_sched_jobs * i];
        }
+
+       ctx->reset_counter = atomic_read(&adev->gpu_reset_counter);
+
        /* create context entity for each ring */
        for (i = 0; i < adev->num_rings; i++) {
                struct amdgpu_ring *ring = adev->rings[i];
index 7dbe85d67d2682854e8158e35f9ee8f8e0e65d94..e41d4baebf86ea39b7e604071d72b0ca29ded612 100644 (file)
@@ -658,12 +658,10 @@ static bool amdgpu_vpost_needed(struct amdgpu_device *adev)
                return false;
 
        if (amdgpu_passthrough(adev)) {
-               /* for FIJI: In whole GPU pass-through virtualization case
-                * old smc fw won't clear some registers (e.g. MEM_SIZE, BIOS_SCRATCH)
-                * so amdgpu_card_posted return false and driver will incorrectly skip vPost.
-                * but if we force vPost do in pass-through case, the driver reload will hang.
-                * whether doing vPost depends on amdgpu_card_posted if smc version is above
-                * 00160e00 for FIJI.
+               /* for FIJI: In whole GPU pass-through virtualization case, after VM reboot
+                * some old smc fw still need driver do vPost otherwise gpu hang, while
+                * those smc fw version above 22.15 doesn't have this flaw, so we force
+                * vpost executed for smc version below 22.15
                 */
                if (adev->asic_type == CHIP_FIJI) {
                        int err;
@@ -674,22 +672,11 @@ static bool amdgpu_vpost_needed(struct amdgpu_device *adev)
                                return true;
 
                        fw_ver = *((uint32_t *)adev->pm.fw->data + 69);
-                       if (fw_ver >= 0x00160e00)
-                               return !amdgpu_card_posted(adev);
+                       if (fw_ver < 0x00160e00)
+                               return true;
                }
-       } else {
-               /* in bare-metal case, amdgpu_card_posted return false
-                * after system reboot/boot, and return true if driver
-                * reloaded.
-                * we shouldn't do vPost after driver reload otherwise GPU
-                * could hang.
-                */
-               if (amdgpu_card_posted(adev))
-                       return false;
        }
-
-       /* we assume vPost is neede for all other cases */
-       return true;
+       return !amdgpu_card_posted(adev);
 }
 
 /**
@@ -1408,16 +1395,6 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
        for (i = 0; i < adev->num_ip_blocks; i++) {
                if (!adev->ip_block_status[i].valid)
                        continue;
-               if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_UVD ||
-                       adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_VCE)
-                       continue;
-               /* enable clockgating to save power */
-               r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
-                                                                   AMD_CG_STATE_GATE);
-               if (r) {
-                       DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n", adev->ip_blocks[i].funcs->name, r);
-                       return r;
-               }
                if (adev->ip_blocks[i].funcs->late_init) {
                        r = adev->ip_blocks[i].funcs->late_init((void *)adev);
                        if (r) {
@@ -1426,6 +1403,18 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
                        }
                        adev->ip_block_status[i].late_initialized = true;
                }
+               /* skip CG for VCE/UVD, it's handled specially */
+               if (adev->ip_blocks[i].type != AMD_IP_BLOCK_TYPE_UVD &&
+                   adev->ip_blocks[i].type != AMD_IP_BLOCK_TYPE_VCE) {
+                       /* enable clockgating to save power */
+                       r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
+                                                                           AMD_CG_STATE_GATE);
+                       if (r) {
+                               DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n",
+                                         adev->ip_blocks[i].funcs->name, r);
+                               return r;
+                       }
+               }
        }
 
        return 0;
@@ -1435,6 +1424,30 @@ static int amdgpu_fini(struct amdgpu_device *adev)
 {
        int i, r;
 
+       /* need to disable SMC first */
+       for (i = 0; i < adev->num_ip_blocks; i++) {
+               if (!adev->ip_block_status[i].hw)
+                       continue;
+               if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_SMC) {
+                       /* ungate blocks before hw fini so that we can shutdown the blocks safely */
+                       r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
+                                                                           AMD_CG_STATE_UNGATE);
+                       if (r) {
+                               DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n",
+                                         adev->ip_blocks[i].funcs->name, r);
+                               return r;
+                       }
+                       r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
+                       /* XXX handle errors */
+                       if (r) {
+                               DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
+                                         adev->ip_blocks[i].funcs->name, r);
+                       }
+                       adev->ip_block_status[i].hw = false;
+                       break;
+               }
+       }
+
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
                if (!adev->ip_block_status[i].hw)
                        continue;
@@ -1480,7 +1493,7 @@ static int amdgpu_fini(struct amdgpu_device *adev)
        return 0;
 }
 
-static int amdgpu_suspend(struct amdgpu_device *adev)
+int amdgpu_suspend(struct amdgpu_device *adev)
 {
        int i, r;
 
@@ -1933,6 +1946,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
        /* evict remaining vram memory */
        amdgpu_bo_evict_vram(adev);
 
+       amdgpu_atombios_scratch_regs_save(adev);
        pci_save_state(dev->pdev);
        if (suspend) {
                /* Shut down the device */
@@ -1984,6 +1998,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
                        return r;
                }
        }
+       amdgpu_atombios_scratch_regs_restore(adev);
 
        /* post card */
        if (!amdgpu_card_posted(adev) || !resume) {
@@ -2073,7 +2088,8 @@ static bool amdgpu_check_soft_reset(struct amdgpu_device *adev)
                if (!adev->ip_block_status[i].valid)
                        continue;
                if (adev->ip_blocks[i].funcs->check_soft_reset)
-                       adev->ip_blocks[i].funcs->check_soft_reset(adev);
+                       adev->ip_block_status[i].hang =
+                               adev->ip_blocks[i].funcs->check_soft_reset(adev);
                if (adev->ip_block_status[i].hang) {
                        DRM_INFO("IP block:%d is hang!\n", i);
                        asic_hang = true;
@@ -2102,12 +2118,20 @@ static int amdgpu_pre_soft_reset(struct amdgpu_device *adev)
 
 static bool amdgpu_need_full_reset(struct amdgpu_device *adev)
 {
-       if (adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang ||
-           adev->ip_block_status[AMD_IP_BLOCK_TYPE_SMC].hang ||
-           adev->ip_block_status[AMD_IP_BLOCK_TYPE_ACP].hang ||
-           adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang) {
-               DRM_INFO("Some block need full reset!\n");
-               return true;
+       int i;
+
+       for (i = 0; i < adev->num_ip_blocks; i++) {
+               if (!adev->ip_block_status[i].valid)
+                       continue;
+               if ((adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) ||
+                   (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_SMC) ||
+                   (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_ACP) ||
+                   (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_DCE)) {
+                       if (adev->ip_block_status[i].hang) {
+                               DRM_INFO("Some block need full reset!\n");
+                               return true;
+                       }
+               }
        }
        return false;
 }
@@ -2233,8 +2257,6 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev)
        }
 
        if (need_full_reset) {
-               /* save scratch */
-               amdgpu_atombios_scratch_regs_save(adev);
                r = amdgpu_suspend(adev);
 
 retry:
@@ -2244,8 +2266,9 @@ retry:
                        amdgpu_display_stop_mc_access(adev, &save);
                        amdgpu_wait_for_idle(adev, AMD_IP_BLOCK_TYPE_GMC);
                }
-
+               amdgpu_atombios_scratch_regs_save(adev);
                r = amdgpu_asic_reset(adev);
+               amdgpu_atombios_scratch_regs_restore(adev);
                /* post card */
                amdgpu_atom_asic_init(adev->mode_info.atom_context);
 
@@ -2253,8 +2276,6 @@ retry:
                        dev_info(adev->dev, "GPU reset succeeded, trying to resume\n");
                        r = amdgpu_resume(adev);
                }
-               /* restore scratch */
-               amdgpu_atombios_scratch_regs_restore(adev);
        }
        if (!r) {
                amdgpu_irq_gpu_reset_resume_helper(adev);
index fe36caf1b7d7b084762d19fb7fa6516a42dd3fa3..14f57d9915e3fc0aa8d5a8e77b734073f05ecb9b 100644 (file)
@@ -113,24 +113,26 @@ void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
        printk("\n");
 }
 
+
 u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev)
 {
        struct drm_device *dev = adev->ddev;
        struct drm_crtc *crtc;
        struct amdgpu_crtc *amdgpu_crtc;
-       u32 line_time_us, vblank_lines;
+       u32 vblank_in_pixels;
        u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
 
        if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        amdgpu_crtc = to_amdgpu_crtc(crtc);
                        if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
-                               line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
-                                       amdgpu_crtc->hw_mode.clock;
-                               vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
+                               vblank_in_pixels =
+                                       amdgpu_crtc->hw_mode.crtc_htotal *
+                                       (amdgpu_crtc->hw_mode.crtc_vblank_end -
                                        amdgpu_crtc->hw_mode.crtc_vdisplay +
-                                       (amdgpu_crtc->v_border * 2);
-                               vblank_time_us = vblank_lines * line_time_us;
+                                       (amdgpu_crtc->v_border * 2));
+
+                               vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock;
                                break;
                        }
                }
index 71ed27eb3ddebd3d2463cc136fb268db74aceb60..e0890deccb2fe31d4deb78deac640d53d8f34a45 100644 (file)
@@ -479,12 +479,15 @@ amdgpu_pci_remove(struct pci_dev *pdev)
 static void
 amdgpu_pci_shutdown(struct pci_dev *pdev)
 {
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct amdgpu_device *adev = dev->dev_private;
+
        /* if we are running in a VM, make sure the device
         * torn down properly on reboot/shutdown.
         * unfortunately we can't detect certain
         * hypervisors so just do this all the time.
         */
-       amdgpu_pci_remove(pdev);
+       amdgpu_suspend(adev);
 }
 
 static int amdgpu_pmops_suspend(struct device *dev)
@@ -735,8 +738,20 @@ static struct pci_driver amdgpu_kms_pci_driver = {
 
 static int __init amdgpu_init(void)
 {
-       amdgpu_sync_init();
-       amdgpu_fence_slab_init();
+       int r;
+
+       r = amdgpu_sync_init();
+       if (r)
+               goto error_sync;
+
+       r = amdgpu_fence_slab_init();
+       if (r)
+               goto error_fence;
+
+       r = amd_sched_fence_slab_init();
+       if (r)
+               goto error_sched;
+
        if (vgacon_text_force()) {
                DRM_ERROR("VGACON disables amdgpu kernel modesetting.\n");
                return -EINVAL;
@@ -748,6 +763,15 @@ static int __init amdgpu_init(void)
        amdgpu_register_atpx_handler();
        /* let modprobe override vga console setting */
        return drm_pci_init(driver, pdriver);
+
+error_sched:
+       amdgpu_fence_slab_fini();
+
+error_fence:
+       amdgpu_sync_fini();
+
+error_sync:
+       return r;
 }
 
 static void __exit amdgpu_exit(void)
@@ -756,6 +780,7 @@ static void __exit amdgpu_exit(void)
        drm_pci_exit(driver, pdriver);
        amdgpu_unregister_atpx_handler();
        amdgpu_sync_fini();
+       amd_sched_fence_slab_fini();
        amdgpu_fence_slab_fini();
 }
 
index 3a2e42f4b897647520f49db963412789672d0229..77b34ec9263215f1cd13d158587589dfa7fb0484 100644 (file)
@@ -68,6 +68,7 @@ int amdgpu_fence_slab_init(void)
 
 void amdgpu_fence_slab_fini(void)
 {
+       rcu_barrier();
        kmem_cache_destroy(amdgpu_fence_slab);
 }
 /*
index 278708f5a744eebb69f0d719bfcb198efcf2ec11..9fa809876339dd47e7cb225af2d8695f7c12b593 100644 (file)
@@ -239,6 +239,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
        if (r) {
                adev->irq.installed = false;
                flush_work(&adev->hotplug_work);
+               cancel_work_sync(&adev->reset_work);
                return r;
        }
 
@@ -264,6 +265,7 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
                if (adev->irq.msi_enabled)
                        pci_disable_msi(adev->pdev);
                flush_work(&adev->hotplug_work);
+               cancel_work_sync(&adev->reset_work);
        }
 
        for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
index c2c7fb140338061f77cc3d2560e2f99f46e37346..3938fca1ea8e5f4c69fd5e0746fcc7ec60c6d2f1 100644 (file)
@@ -99,6 +99,8 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags)
 
        if ((amdgpu_runtime_pm != 0) &&
            amdgpu_has_atpx() &&
+           (amdgpu_is_atpx_hybrid() ||
+            amdgpu_has_atpx_dgpu_power_cntl()) &&
            ((flags & AMD_IS_APU) == 0))
                flags |= AMD_IS_PX;
 
@@ -459,10 +461,8 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                /* return all clocks in KHz */
                dev_info.gpu_counter_freq = amdgpu_asic_get_xclk(adev) * 10;
                if (adev->pm.dpm_enabled) {
-                       dev_info.max_engine_clock =
-                               adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk * 10;
-                       dev_info.max_memory_clock =
-                               adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk * 10;
+                       dev_info.max_engine_clock = amdgpu_dpm_get_sclk(adev, false) * 10;
+                       dev_info.max_memory_clock = amdgpu_dpm_get_mclk(adev, false) * 10;
                } else {
                        dev_info.max_engine_clock = adev->pm.default_sclk * 10;
                        dev_info.max_memory_clock = adev->pm.default_mclk * 10;
index aa074fac0c7f66ef796b2da0704c314c96f2b5d5..f3efb1c5dae96469ecdb6944e991f832b43e26dd 100644 (file)
@@ -754,6 +754,10 @@ static const char *amdgpu_vram_names[] = {
 
 int amdgpu_bo_init(struct amdgpu_device *adev)
 {
+       /* reserve PAT memory space to WC for VRAM */
+       arch_io_reserve_memtype_wc(adev->mc.aper_base,
+                                  adev->mc.aper_size);
+
        /* Add an MTRR for the VRAM */
        adev->mc.vram_mtrr = arch_phys_wc_add(adev->mc.aper_base,
                                              adev->mc.aper_size);
@@ -769,6 +773,7 @@ void amdgpu_bo_fini(struct amdgpu_device *adev)
 {
        amdgpu_ttm_fini(adev);
        arch_phys_wc_del(adev->mc.vram_mtrr);
+       arch_io_free_memtype_wc(adev->mc.aper_base, adev->mc.aper_size);
 }
 
 int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
index 7700dc22f2432bb3f6d020a7c3acf3f3ccaaae9f..3826d5aea0a6a55d00d9aae2bda9f7b04489ec60 100644 (file)
@@ -74,20 +74,36 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
        if (ret)
                return ERR_PTR(ret);
 
+       bo->prime_shared_count = 1;
        return &bo->gem_base;
 }
 
 int amdgpu_gem_prime_pin(struct drm_gem_object *obj)
 {
        struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
-       int ret = 0;
+       long ret = 0;
 
        ret = amdgpu_bo_reserve(bo, false);
        if (unlikely(ret != 0))
                return ret;
 
+       /*
+        * Wait for all shared fences to complete before we switch to future
+        * use of exclusive fence on this prime shared bo.
+        */
+       ret = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, false,
+                                                 MAX_SCHEDULE_TIMEOUT);
+       if (unlikely(ret < 0)) {
+               DRM_DEBUG_PRIME("Fence wait failed: %li\n", ret);
+               amdgpu_bo_unreserve(bo);
+               return ret;
+       }
+
        /* pin buffer into GTT */
        ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL);
+       if (likely(ret == 0))
+               bo->prime_shared_count++;
+
        amdgpu_bo_unreserve(bo);
        return ret;
 }
@@ -102,6 +118,8 @@ void amdgpu_gem_prime_unpin(struct drm_gem_object *obj)
                return;
 
        amdgpu_bo_unpin(bo);
+       if (bo->prime_shared_count)
+               bo->prime_shared_count--;
        amdgpu_bo_unreserve(bo);
 }
 
index e1fa8731d1e2db7b16c09edf44d195e8d457cf07..3cb5e903cd62896529d2ea18d5ea7f49c2feae73 100644 (file)
@@ -345,8 +345,8 @@ static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
        ent = debugfs_create_file(name,
                                  S_IFREG | S_IRUGO, root,
                                  ring, &amdgpu_debugfs_ring_fops);
-       if (IS_ERR(ent))
-               return PTR_ERR(ent);
+       if (!ent)
+               return -ENOMEM;
 
        i_size_write(ent->d_inode, ring->ring_size + 12);
        ring->ent = ent;
index 887483b8b818383c5139ec8c2059e3fd19f16014..dcaf691f56b5577352d2238bdfd27e2f1aca2386 100644 (file)
@@ -555,10 +555,13 @@ struct amdgpu_ttm_tt {
 int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
 {
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
-       int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
+       unsigned int flags = 0;
        unsigned pinned = 0;
        int r;
 
+       if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY))
+               flags |= FOLL_WRITE;
+
        if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
                /* check that we only use anonymous memory
                   to prevent problems with writeback */
@@ -581,7 +584,7 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
                list_add(&guptask.list, &gtt->guptasks);
                spin_unlock(&gtt->guptasklock);
 
-               r = get_user_pages(userptr, num_pages, write, 0, p, NULL);
+               r = get_user_pages(userptr, num_pages, flags, p, NULL);
 
                spin_lock(&gtt->guptasklock);
                list_del(&guptask.list);
index 06f24322e7c31bcfbb9dc867909ebe234968accb..968c4260d7a7e0ccfa94f4a3f069acc9f73e1830 100644 (file)
@@ -1758,5 +1758,6 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
                fence_put(adev->vm_manager.ids[i].first);
                amdgpu_sync_free(&adev->vm_manager.ids[i].active);
                fence_put(id->flushed_updates);
+               fence_put(id->last_flush);
        }
 }
index 1d8c375a3561c9f872a4d87c0b435048f5a4b10b..5be788b269e22232a61b75e83bdd822bf142c583 100644 (file)
@@ -4075,7 +4075,7 @@ static int ci_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
                                                          pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
                }
        } else {
-               if (pi->last_mclk_dpm_enable_mask & 0x1) {
+               if (pi->uvd_enabled) {
                        pi->uvd_enabled = false;
                        pi->dpm_level_enable_mask.mclk_dpm_enable_mask |= 1;
                        amdgpu_ci_send_msg_to_smc_with_parameter(adev,
@@ -6236,6 +6236,8 @@ static int ci_dpm_sw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       flush_work(&adev->pm.dpm.thermal.work);
+
        mutex_lock(&adev->pm.mutex);
        amdgpu_pm_sysfs_fini(adev);
        ci_dpm_fini(adev);
index f80a0834e889e8ff07b77846f28fcb619632ca14..3c082e1437303d3247da620fcd08ba8a031e62e0 100644 (file)
@@ -1514,14 +1514,16 @@ static int cz_dpm_set_powergating_state(void *handle,
        return 0;
 }
 
-/* borrowed from KV, need future unify */
 static int cz_dpm_get_temperature(struct amdgpu_device *adev)
 {
        int actual_temp = 0;
-       uint32_t temp = RREG32_SMC(0xC0300E0C);
+       uint32_t val = RREG32_SMC(ixTHM_TCON_CUR_TMP);
+       uint32_t temp = REG_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP);
 
-       if (temp)
+       if (REG_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP_RANGE_SEL))
                actual_temp = 1000 * ((temp / 8) - 49);
+       else
+               actual_temp = 1000 * (temp / 8);
 
        return actual_temp;
 }
index 613ebb7ed50f5e33699fb254bd417b238f6c2783..9260caef74fa07f7045f1bbc30e5481bb6f5558e 100644 (file)
@@ -3151,10 +3151,6 @@ static int dce_v10_0_hw_fini(void *handle)
 
 static int dce_v10_0_suspend(void *handle)
 {
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       amdgpu_atombios_scratch_regs_save(adev);
-
        return dce_v10_0_hw_fini(handle);
 }
 
@@ -3165,8 +3161,6 @@ static int dce_v10_0_resume(void *handle)
 
        ret = dce_v10_0_hw_init(handle);
 
-       amdgpu_atombios_scratch_regs_restore(adev);
-
        /* turn on the BL */
        if (adev->mode_info.bl_encoder) {
                u8 bl_level = amdgpu_display_backlight_get_level(adev,
@@ -3188,16 +3182,11 @@ static int dce_v10_0_wait_for_idle(void *handle)
        return 0;
 }
 
-static int dce_v10_0_check_soft_reset(void *handle)
+static bool dce_v10_0_check_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (dce_v10_0_is_display_hung(adev))
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = true;
-       else
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang = false;
-
-       return 0;
+       return dce_v10_0_is_display_hung(adev);
 }
 
 static int dce_v10_0_soft_reset(void *handle)
@@ -3205,9 +3194,6 @@ static int dce_v10_0_soft_reset(void *handle)
        u32 srbm_soft_reset = 0, tmp;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_DCE].hang)
-               return 0;
-
        if (dce_v10_0_is_display_hung(adev))
                srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
 
index f264b8f17ad1b302ebb51f0f37a1805655529470..367739bd19279fa5f968675b54733bad289b65e0 100644 (file)
@@ -3215,10 +3215,6 @@ static int dce_v11_0_hw_fini(void *handle)
 
 static int dce_v11_0_suspend(void *handle)
 {
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       amdgpu_atombios_scratch_regs_save(adev);
-
        return dce_v11_0_hw_fini(handle);
 }
 
@@ -3229,8 +3225,6 @@ static int dce_v11_0_resume(void *handle)
 
        ret = dce_v11_0_hw_init(handle);
 
-       amdgpu_atombios_scratch_regs_restore(adev);
-
        /* turn on the BL */
        if (adev->mode_info.bl_encoder) {
                u8 bl_level = amdgpu_display_backlight_get_level(adev,
index b948d6cb139936670228d6a9e805ecd7fbe9b225..15f9fc0514b29b800f1fb5c83cfd3f43ea52ec04 100644 (file)
@@ -2482,10 +2482,6 @@ static int dce_v6_0_hw_fini(void *handle)
 
 static int dce_v6_0_suspend(void *handle)
 {
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       amdgpu_atombios_scratch_regs_save(adev);
-
        return dce_v6_0_hw_fini(handle);
 }
 
@@ -2496,8 +2492,6 @@ static int dce_v6_0_resume(void *handle)
 
        ret = dce_v6_0_hw_init(handle);
 
-       amdgpu_atombios_scratch_regs_restore(adev);
-
        /* turn on the BL */
        if (adev->mode_info.bl_encoder) {
                u8 bl_level = amdgpu_display_backlight_get_level(adev,
index 5966166ec94c886d48035f1492b42ea89a24d354..8c4d808db0f1279af1b5a0c05e364c6e6c07bdfd 100644 (file)
@@ -3033,10 +3033,6 @@ static int dce_v8_0_hw_fini(void *handle)
 
 static int dce_v8_0_suspend(void *handle)
 {
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       amdgpu_atombios_scratch_regs_save(adev);
-
        return dce_v8_0_hw_fini(handle);
 }
 
@@ -3047,8 +3043,6 @@ static int dce_v8_0_resume(void *handle)
 
        ret = dce_v8_0_hw_init(handle);
 
-       amdgpu_atombios_scratch_regs_restore(adev);
-
        /* turn on the BL */
        if (adev->mode_info.bl_encoder) {
                u8 bl_level = amdgpu_display_backlight_get_level(adev,
index 6c6ff57b1c95f2824537933c8c8ecd6525bda3ab..bb97182dc74991ae5b5ad0ab5d4121757ae54789 100644 (file)
@@ -640,7 +640,6 @@ static const u32 stoney_mgcg_cgcg_init[] =
        mmCP_MEM_SLP_CNTL, 0xffffffff, 0x00020201,
        mmRLC_MEM_SLP_CNTL, 0xffffffff, 0x00020201,
        mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200,
-       mmATC_MISC_CG, 0xffffffff, 0x000c0200,
 };
 
 static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev);
@@ -4087,14 +4086,21 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev)
 static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev)
 {
        int r;
+       u32 tmp;
 
        gfx_v8_0_rlc_stop(adev);
 
        /* disable CG */
-       WREG32(mmRLC_CGCG_CGLS_CTRL, 0);
+       tmp = RREG32(mmRLC_CGCG_CGLS_CTRL);
+       tmp &= ~(RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK |
+                RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
+       WREG32(mmRLC_CGCG_CGLS_CTRL, tmp);
        if (adev->asic_type == CHIP_POLARIS11 ||
-           adev->asic_type == CHIP_POLARIS10)
-               WREG32(mmRLC_CGCG_CGLS_CTRL_3D, 0);
+           adev->asic_type == CHIP_POLARIS10) {
+               tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D);
+               tmp &= ~0x3;
+               WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp);
+       }
 
        /* disable PG */
        WREG32(mmRLC_PG_CNTL, 0);
@@ -5137,7 +5143,7 @@ static int gfx_v8_0_wait_for_idle(void *handle)
        return -ETIMEDOUT;
 }
 
-static int gfx_v8_0_check_soft_reset(void *handle)
+static bool gfx_v8_0_check_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
@@ -5189,16 +5195,14 @@ static int gfx_v8_0_check_soft_reset(void *handle)
                                                SRBM_SOFT_RESET, SOFT_RESET_SEM, 1);
 
        if (grbm_soft_reset || srbm_soft_reset) {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = true;
                adev->gfx.grbm_soft_reset = grbm_soft_reset;
                adev->gfx.srbm_soft_reset = srbm_soft_reset;
+               return true;
        } else {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang = false;
                adev->gfx.grbm_soft_reset = 0;
                adev->gfx.srbm_soft_reset = 0;
+               return false;
        }
-
-       return 0;
 }
 
 static void gfx_v8_0_inactive_hqd(struct amdgpu_device *adev,
@@ -5226,7 +5230,8 @@ static int gfx_v8_0_pre_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang)
+       if ((!adev->gfx.grbm_soft_reset) &&
+           (!adev->gfx.srbm_soft_reset))
                return 0;
 
        grbm_soft_reset = adev->gfx.grbm_soft_reset;
@@ -5264,7 +5269,8 @@ static int gfx_v8_0_soft_reset(void *handle)
        u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
        u32 tmp;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang)
+       if ((!adev->gfx.grbm_soft_reset) &&
+           (!adev->gfx.srbm_soft_reset))
                return 0;
 
        grbm_soft_reset = adev->gfx.grbm_soft_reset;
@@ -5334,7 +5340,8 @@ static int gfx_v8_0_post_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GFX].hang)
+       if ((!adev->gfx.grbm_soft_reset) &&
+           (!adev->gfx.srbm_soft_reset))
                return 0;
 
        grbm_soft_reset = adev->gfx.grbm_soft_reset;
index 1b319f5bc6962d5d6250db12fcb18302db789ade..a16b2201d52cac3a53870e7253e1d367160765ef 100644 (file)
@@ -100,6 +100,7 @@ static const u32 cz_mgcg_cgcg_init[] =
 
 static const u32 stoney_mgcg_cgcg_init[] =
 {
+       mmATC_MISC_CG, 0xffffffff, 0x000c0200,
        mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
 };
 
@@ -1099,7 +1100,7 @@ static int gmc_v8_0_wait_for_idle(void *handle)
 
 }
 
-static int gmc_v8_0_check_soft_reset(void *handle)
+static bool gmc_v8_0_check_soft_reset(void *handle)
 {
        u32 srbm_soft_reset = 0;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1116,20 +1117,19 @@ static int gmc_v8_0_check_soft_reset(void *handle)
                                                        SRBM_SOFT_RESET, SOFT_RESET_MC, 1);
        }
        if (srbm_soft_reset) {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = true;
                adev->mc.srbm_soft_reset = srbm_soft_reset;
+               return true;
        } else {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang = false;
                adev->mc.srbm_soft_reset = 0;
+               return false;
        }
-       return 0;
 }
 
 static int gmc_v8_0_pre_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang)
+       if (!adev->mc.srbm_soft_reset)
                return 0;
 
        gmc_v8_0_mc_stop(adev, &adev->mc.save);
@@ -1145,7 +1145,7 @@ static int gmc_v8_0_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang)
+       if (!adev->mc.srbm_soft_reset)
                return 0;
        srbm_soft_reset = adev->mc.srbm_soft_reset;
 
@@ -1175,7 +1175,7 @@ static int gmc_v8_0_post_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_GMC].hang)
+       if (!adev->mc.srbm_soft_reset)
                return 0;
 
        gmc_v8_0_mc_resume(adev, &adev->mc.save);
index f8618a3881a841a3160115eabd065a9b311f862b..71d2856222fa9be710be004ad40f3d32c5ab17cb 100644 (file)
@@ -3063,6 +3063,8 @@ static int kv_dpm_sw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       flush_work(&adev->pm.dpm.thermal.work);
+
        mutex_lock(&adev->pm.mutex);
        amdgpu_pm_sysfs_fini(adev);
        kv_dpm_fini(adev);
index f325fd86430b9e3d565f28fd5b11ace2c2a76667..a9d10941fb53d9ab2290fd6bdbe3351d91b0acaa 100644 (file)
@@ -1268,7 +1268,7 @@ static int sdma_v3_0_wait_for_idle(void *handle)
        return -ETIMEDOUT;
 }
 
-static int sdma_v3_0_check_soft_reset(void *handle)
+static bool sdma_v3_0_check_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset = 0;
@@ -1281,14 +1281,12 @@ static int sdma_v3_0_check_soft_reset(void *handle)
        }
 
        if (srbm_soft_reset) {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = true;
                adev->sdma.srbm_soft_reset = srbm_soft_reset;
+               return true;
        } else {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang = false;
                adev->sdma.srbm_soft_reset = 0;
+               return false;
        }
-
-       return 0;
 }
 
 static int sdma_v3_0_pre_soft_reset(void *handle)
@@ -1296,7 +1294,7 @@ static int sdma_v3_0_pre_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset = 0;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang)
+       if (!adev->sdma.srbm_soft_reset)
                return 0;
 
        srbm_soft_reset = adev->sdma.srbm_soft_reset;
@@ -1315,7 +1313,7 @@ static int sdma_v3_0_post_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset = 0;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang)
+       if (!adev->sdma.srbm_soft_reset)
                return 0;
 
        srbm_soft_reset = adev->sdma.srbm_soft_reset;
@@ -1335,7 +1333,7 @@ static int sdma_v3_0_soft_reset(void *handle)
        u32 srbm_soft_reset = 0;
        u32 tmp;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_SDMA].hang)
+       if (!adev->sdma.srbm_soft_reset)
                return 0;
 
        srbm_soft_reset = adev->sdma.srbm_soft_reset;
index 8bd08925b370b753fbe217031c1e29e5b3b4426e..d6f85b1a0b93540e60399b337310cee3be6753c0 100644 (file)
@@ -3477,6 +3477,49 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
        int i;
        struct si_dpm_quirk *p = si_dpm_quirk_list;
 
+       /* limit all SI kickers */
+       if (adev->asic_type == CHIP_PITCAIRN) {
+               if ((adev->pdev->revision == 0x81) ||
+                   (adev->pdev->device == 0x6810) ||
+                   (adev->pdev->device == 0x6811) ||
+                   (adev->pdev->device == 0x6816) ||
+                   (adev->pdev->device == 0x6817) ||
+                   (adev->pdev->device == 0x6806))
+                       max_mclk = 120000;
+       } else if (adev->asic_type == CHIP_VERDE) {
+               if ((adev->pdev->revision == 0x81) ||
+                   (adev->pdev->revision == 0x83) ||
+                   (adev->pdev->revision == 0x87) ||
+                   (adev->pdev->device == 0x6820) ||
+                   (adev->pdev->device == 0x6821) ||
+                   (adev->pdev->device == 0x6822) ||
+                   (adev->pdev->device == 0x6823) ||
+                   (adev->pdev->device == 0x682A) ||
+                   (adev->pdev->device == 0x682B)) {
+                       max_sclk = 75000;
+                       max_mclk = 80000;
+               }
+       } else if (adev->asic_type == CHIP_OLAND) {
+               if ((adev->pdev->revision == 0xC7) ||
+                   (adev->pdev->revision == 0x80) ||
+                   (adev->pdev->revision == 0x81) ||
+                   (adev->pdev->revision == 0x83) ||
+                   (adev->pdev->device == 0x6604) ||
+                   (adev->pdev->device == 0x6605)) {
+                       max_sclk = 75000;
+                       max_mclk = 80000;
+               }
+       } else if (adev->asic_type == CHIP_HAINAN) {
+               if ((adev->pdev->revision == 0x81) ||
+                   (adev->pdev->revision == 0x83) ||
+                   (adev->pdev->revision == 0xC3) ||
+                   (adev->pdev->device == 0x6664) ||
+                   (adev->pdev->device == 0x6665) ||
+                   (adev->pdev->device == 0x6667)) {
+                       max_sclk = 75000;
+                       max_mclk = 80000;
+               }
+       }
        /* Apply dpm quirks */
        while (p && p->chip_device != 0) {
                if (adev->pdev->vendor == p->chip_vendor &&
@@ -3489,16 +3532,6 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
                }
                ++p;
        }
-       /* limit mclk on all R7 370 parts for stability */
-       if (adev->pdev->device == 0x6811 &&
-           adev->pdev->revision == 0x81)
-               max_mclk = 120000;
-       /* limit sclk/mclk on Jet parts for stability */
-       if (adev->pdev->device == 0x6665 &&
-           adev->pdev->revision == 0xc3) {
-               max_sclk = 75000;
-               max_mclk = 80000;
-       }
 
        if (rps->vce_active) {
                rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk;
@@ -7771,6 +7804,8 @@ static int si_dpm_sw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       flush_work(&adev->pm.dpm.thermal.work);
+
        mutex_lock(&adev->pm.mutex);
        amdgpu_pm_sysfs_fini(adev);
        si_dpm_fini(adev);
index d127d59f953a8ded522884fa7f9eba77e648db2d..b4ea229bb4498ff1f84209dec7f211198ed788ed 100644 (file)
@@ -373,7 +373,7 @@ static int tonga_ih_wait_for_idle(void *handle)
        return -ETIMEDOUT;
 }
 
-static int tonga_ih_check_soft_reset(void *handle)
+static bool tonga_ih_check_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset = 0;
@@ -384,21 +384,19 @@ static int tonga_ih_check_soft_reset(void *handle)
                                                SOFT_RESET_IH, 1);
 
        if (srbm_soft_reset) {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = true;
                adev->irq.srbm_soft_reset = srbm_soft_reset;
+               return true;
        } else {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang = false;
                adev->irq.srbm_soft_reset = 0;
+               return false;
        }
-
-       return 0;
 }
 
 static int tonga_ih_pre_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang)
+       if (!adev->irq.srbm_soft_reset)
                return 0;
 
        return tonga_ih_hw_fini(adev);
@@ -408,7 +406,7 @@ static int tonga_ih_post_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang)
+       if (!adev->irq.srbm_soft_reset)
                return 0;
 
        return tonga_ih_hw_init(adev);
@@ -419,7 +417,7 @@ static int tonga_ih_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_IH].hang)
+       if (!adev->irq.srbm_soft_reset)
                return 0;
        srbm_soft_reset = adev->irq.srbm_soft_reset;
 
index e0fd9f21ed9585ce37c310605f2ea56524fa60bc..ab3df6d756562ee33b97d2c48aaf6f7bfadc6f2a 100644 (file)
@@ -770,7 +770,7 @@ static int uvd_v6_0_wait_for_idle(void *handle)
 }
 
 #define AMDGPU_UVD_STATUS_BUSY_MASK    0xfd
-static int uvd_v6_0_check_soft_reset(void *handle)
+static bool uvd_v6_0_check_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset = 0;
@@ -782,19 +782,19 @@ static int uvd_v6_0_check_soft_reset(void *handle)
                srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_UVD, 1);
 
        if (srbm_soft_reset) {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = true;
                adev->uvd.srbm_soft_reset = srbm_soft_reset;
+               return true;
        } else {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang = false;
                adev->uvd.srbm_soft_reset = 0;
+               return false;
        }
-       return 0;
 }
+
 static int uvd_v6_0_pre_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+       if (!adev->uvd.srbm_soft_reset)
                return 0;
 
        uvd_v6_0_stop(adev);
@@ -806,7 +806,7 @@ static int uvd_v6_0_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+       if (!adev->uvd.srbm_soft_reset)
                return 0;
        srbm_soft_reset = adev->uvd.srbm_soft_reset;
 
@@ -836,7 +836,7 @@ static int uvd_v6_0_post_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_UVD].hang)
+       if (!adev->uvd.srbm_soft_reset)
                return 0;
 
        mdelay(5);
index 3f6db4ec0102d0f54d2b5cba6c33a76b9d64ad46..6feed726e299378e39d08cf74f5d7e71b20a2cc4 100644 (file)
@@ -52,6 +52,8 @@
 #define VCE_V3_0_STACK_SIZE    (64 * 1024)
 #define VCE_V3_0_DATA_SIZE     ((16 * 1024 * AMDGPU_MAX_VCE_HANDLES) + (52 * 1024))
 
+#define FW_52_8_3      ((52 << 24) | (8 << 16) | (3 << 8))
+
 static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx);
 static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev);
 static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev);
@@ -382,6 +384,10 @@ static int vce_v3_0_sw_init(void *handle)
        if (r)
                return r;
 
+       /* 52.8.3 required for 3 ring support */
+       if (adev->vce.fw_version < FW_52_8_3)
+               adev->vce.num_rings = 2;
+
        r = amdgpu_vce_resume(adev);
        if (r)
                return r;
@@ -561,7 +567,7 @@ static int vce_v3_0_wait_for_idle(void *handle)
 #define  AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \
                                      VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK)
 
-static int vce_v3_0_check_soft_reset(void *handle)
+static bool vce_v3_0_check_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset = 0;
@@ -591,16 +597,15 @@ static int vce_v3_0_check_soft_reset(void *handle)
                srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
        }
        WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
+       mutex_unlock(&adev->grbm_idx_mutex);
 
        if (srbm_soft_reset) {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = true;
                adev->vce.srbm_soft_reset = srbm_soft_reset;
+               return true;
        } else {
-               adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang = false;
                adev->vce.srbm_soft_reset = 0;
+               return false;
        }
-       mutex_unlock(&adev->grbm_idx_mutex);
-       return 0;
 }
 
 static int vce_v3_0_soft_reset(void *handle)
@@ -608,7 +613,7 @@ static int vce_v3_0_soft_reset(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        u32 srbm_soft_reset;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
+       if (!adev->vce.srbm_soft_reset)
                return 0;
        srbm_soft_reset = adev->vce.srbm_soft_reset;
 
@@ -638,7 +643,7 @@ static int vce_v3_0_pre_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
+       if (!adev->vce.srbm_soft_reset)
                return 0;
 
        mdelay(5);
@@ -651,7 +656,7 @@ static int vce_v3_0_post_soft_reset(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       if (!adev->ip_block_status[AMD_IP_BLOCK_TYPE_VCE].hang)
+       if (!adev->vce.srbm_soft_reset)
                return 0;
 
        mdelay(5);
index c0d9aad7126f4a16e067e19e76067d0a3248e8d9..f62f1a74f890d0d806506f343bb14ec6090578e9 100644 (file)
@@ -80,7 +80,9 @@
 #include "dce_virtual.h"
 
 MODULE_FIRMWARE("amdgpu/topaz_smc.bin");
+MODULE_FIRMWARE("amdgpu/topaz_k_smc.bin");
 MODULE_FIRMWARE("amdgpu/tonga_smc.bin");
+MODULE_FIRMWARE("amdgpu/tonga_k_smc.bin");
 MODULE_FIRMWARE("amdgpu/fiji_smc.bin");
 MODULE_FIRMWARE("amdgpu/polaris10_smc.bin");
 MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin");
@@ -1651,7 +1653,7 @@ static int vi_common_early_init(void *handle)
                        AMD_CG_SUPPORT_SDMA_MGCG |
                        AMD_CG_SUPPORT_SDMA_LS |
                        AMD_CG_SUPPORT_VCE_MGCG;
-               adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
+               adev->pg_flags = AMD_PG_SUPPORT_GFX_PG |
                        AMD_PG_SUPPORT_GFX_SMG |
                        AMD_PG_SUPPORT_GFX_PIPELINE |
                        AMD_PG_SUPPORT_UVD |
index c934b78c9e2f056b9ba20ec9f2b182cfa1910e74..bec8125bceb0d2555b49b8badaafbf4494ac47f7 100644 (file)
@@ -165,7 +165,7 @@ struct amd_ip_funcs {
        /* poll for idle */
        int (*wait_for_idle)(void *handle);
        /* check soft reset the IP block */
-       int (*check_soft_reset)(void *handle);
+       bool (*check_soft_reset)(void *handle);
        /* pre soft reset the IP block */
        int (*pre_soft_reset)(void *handle);
        /* soft reset the IP block */
index 92b1178438755ab4e981dfa14741f62a3353da9f..8cee4e0f9fde60c736b56344b378c67c2107d867 100644 (file)
@@ -49,6 +49,7 @@ static const pem_event_action * const uninitialize_event[] = {
        uninitialize_display_phy_access_tasks,
        disable_gfx_voltage_island_power_gating_tasks,
        disable_gfx_clock_gating_tasks,
+       uninitialize_thermal_controller_tasks,
        set_boot_state_tasks,
        adjust_power_state_tasks,
        disable_dynamic_state_management_tasks,
index 7e4fcbbbe08652735c6796a2cbfd62d122434e69..960424913496d671d70fa220600fab6874dbd67d 100644 (file)
@@ -1785,6 +1785,21 @@ static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_c
        return 0;
 }
 
+static int cz_thermal_get_temperature(struct pp_hwmgr *hwmgr)
+{
+       int actual_temp = 0;
+       uint32_t val = cgs_read_ind_register(hwmgr->device,
+                                            CGS_IND_REG__SMC, ixTHM_TCON_CUR_TMP);
+       uint32_t temp = PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP);
+
+       if (PHM_GET_FIELD(val, THM_TCON_CUR_TMP, CUR_TEMP_RANGE_SEL))
+               actual_temp = ((temp / 8) - 49) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       else
+               actual_temp = (temp / 8) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
+
+       return actual_temp;
+}
+
 static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value)
 {
        struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
@@ -1881,6 +1896,9 @@ static int cz_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value)
        case AMDGPU_PP_SENSOR_VCE_POWER:
                *value = cz_hwmgr->vce_power_gated ? 0 : 1;
                return 0;
+       case AMDGPU_PP_SENSOR_GPU_TEMP:
+               *value = cz_thermal_get_temperature(hwmgr);
+               return 0;
        default:
                return -EINVAL;
        }
index 14f8c1f4da3d7a385202f2e8ec24ee5e6ab0f3ad..0723758ed0650616ee111af60e9ac14287f73ae2 100644 (file)
@@ -272,7 +272,7 @@ bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hw
        PHM_FUNC_CHECK(hwmgr);
 
        if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL)
-               return -EINVAL;
+               return false;
 
        return hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration(hwmgr);
 }
index 1167205057b337d7f968f08d4218487c218797a9..e03dcb6ea9c17c0a3ea5dbf7dc547bf8b55464af 100644 (file)
@@ -710,13 +710,15 @@ int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
        uint32_t vol;
        int ret = 0;
 
-       if (hwmgr->chip_id < CHIP_POLARIS10) {
-               atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage);
+       if (hwmgr->chip_id < CHIP_TONGA) {
+               ret = atomctrl_get_voltage_evv(hwmgr, id, voltage);
+       } else if (hwmgr->chip_id < CHIP_POLARIS10) {
+               ret = atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage);
                if (*voltage >= 2000 || *voltage == 0)
                        *voltage = 1150;
        } else {
                ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol);
-               *voltage = (uint16_t)vol/100;
+               *voltage = (uint16_t)(vol/100);
        }
        return ret;
 }
index 1126bd4f74dcc61d6e48c452ec281723b2fe81ec..0894527d932f4849cbe147eba4298a6a2f36264d 100644 (file)
@@ -1320,7 +1320,8 @@ int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_
        if (0 != result)
                return result;
 
-       *voltage = le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3 *)(&get_voltage_info_param_space))->ulVoltageLevel);
+       *voltage = le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3 *)
+                               (&get_voltage_info_param_space))->ulVoltageLevel);
 
        return result;
 }
index 7de701d8a450a624bcc57c9802338676ab573b0b..4477c55a58e32f903d33005cf9f2cc13a07215ba 100644 (file)
@@ -1201,12 +1201,15 @@ static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr,
 static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr)
 {
        const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
-       const ATOM_Tonga_VCE_State_Table *vce_state_table =
-                               (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pp_table) + le16_to_cpu(pp_table->usVCEStateTableOffset));
+       const ATOM_Tonga_VCE_State_Table *vce_state_table;
 
-       if (vce_state_table == NULL)
+
+       if (pp_table == NULL)
                return 0;
 
+       vce_state_table = (void *)pp_table +
+                       le16_to_cpu(pp_table->usVCEStateTableOffset);
+
        return vce_state_table->ucNumEntries;
 }
 
index 508245d49d3394055835683f3067e021f6d482d0..08cd0bd3ebe5b1e34b14940a4cff4805027518e1 100644 (file)
@@ -1030,20 +1030,19 @@ static int smu7_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 
        /* disable SCLK dpm */
-       if (!data->sclk_dpm_key_disabled)
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_DPM_Disable) == 0),
-                               "Failed to disable SCLK DPM!",
-                               return -EINVAL);
+       if (!data->sclk_dpm_key_disabled) {
+               PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
+                               "Trying to disable SCLK DPM when DPM is disabled",
+                               return 0);
+               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Disable);
+       }
 
        /* disable MCLK dpm */
        if (!data->mclk_dpm_key_disabled) {
-               PP_ASSERT_WITH_CODE(
-                               (smum_send_msg_to_smc(hwmgr->smumgr,
-                                               PPSMC_MSG_MCLKDPM_Disable) == 0),
-                               "Failed to disable MCLK DPM!",
-                               return -EINVAL);
+               PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
+                               "Trying to disable MCLK DPM when DPM is disabled",
+                               return 0);
+               smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MCLKDPM_Disable);
        }
 
        return 0;
@@ -1069,10 +1068,13 @@ static int smu7_stop_dpm(struct pp_hwmgr *hwmgr)
                                return -EINVAL);
        }
 
-       if (smu7_disable_sclk_mclk_dpm(hwmgr)) {
-               printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!");
-               return -EINVAL;
-       }
+       smu7_disable_sclk_mclk_dpm(hwmgr);
+
+       PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
+                       "Trying to disable voltage DPM when DPM is disabled",
+                       return 0);
+
+       smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Voltage_Cntl_Disable);
 
        return 0;
 }
@@ -1166,8 +1168,8 @@ int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
 
        tmp_result = (!smum_is_dpm_running(hwmgr)) ? 0 : -1;
        PP_ASSERT_WITH_CODE(tmp_result == 0,
-                       "DPM is already running right now, no need to enable DPM!",
-                       return 0);
+                       "DPM is already running",
+                       );
 
        if (smu7_voltage_control(hwmgr)) {
                tmp_result = smu7_enable_voltage_control(hwmgr);
@@ -1226,7 +1228,7 @@ int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
        PP_ASSERT_WITH_CODE((0 == tmp_result),
                        "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
 
-       smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_HasDisplay);
+       smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_NoDisplay);
 
        tmp_result = smu7_enable_sclk_control(hwmgr);
        PP_ASSERT_WITH_CODE((0 == tmp_result),
@@ -1306,6 +1308,12 @@ int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
        PP_ASSERT_WITH_CODE((tmp_result == 0),
                        "Failed to disable thermal auto throttle!", result = tmp_result);
 
+       if (1 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) {
+               PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableAvfs)),
+                                       "Failed to disable AVFS!",
+                                       return -EINVAL);
+       }
+
        tmp_result = smu7_stop_dpm(hwmgr);
        PP_ASSERT_WITH_CODE((tmp_result == 0),
                        "Failed to stop DPM!", result = tmp_result);
@@ -1452,17 +1460,17 @@ static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr)
        struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = NULL;
 
 
-       if (table_info != NULL)
-               sclk_table = table_info->vdd_dep_on_sclk;
-
        for (i = 0; i < SMU7_MAX_LEAKAGE_COUNT; i++) {
                vv_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
 
                if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
-                       if (0 == phm_get_sclk_for_voltage_evv(hwmgr,
+                       if ((hwmgr->pp_table_version == PP_TABLE_V1)
+                           && !phm_get_sclk_for_voltage_evv(hwmgr,
                                                table_info->vddgfx_lookup_table, vv_id, &sclk)) {
                                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                                                        PHM_PlatformCaps_ClockStretcher)) {
+                                       sclk_table = table_info->vdd_dep_on_sclk;
+
                                        for (j = 1; j < sclk_table->count; j++) {
                                                if (sclk_table->entries[j].clk == sclk &&
                                                                sclk_table->entries[j].cks_enable == 0) {
@@ -1488,12 +1496,15 @@ static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr)
                                }
                        }
                } else {
-
                        if ((hwmgr->pp_table_version == PP_TABLE_V0)
                                || !phm_get_sclk_for_voltage_evv(hwmgr,
                                        table_info->vddc_lookup_table, vv_id, &sclk)) {
                                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                                                PHM_PlatformCaps_ClockStretcher)) {
+                                       if (table_info == NULL)
+                                               return -EINVAL;
+                                       sclk_table = table_info->vdd_dep_on_sclk;
+
                                        for (j = 1; j < sclk_table->count; j++) {
                                                if (sclk_table->entries[j].clk == sclk &&
                                                                sclk_table->entries[j].cks_enable == 0) {
@@ -2117,15 +2128,20 @@ static int smu7_patch_acp_vddc(struct pp_hwmgr *hwmgr,
 }
 
 static int smu7_patch_limits_vddc(struct pp_hwmgr *hwmgr,
-                                    struct phm_clock_and_voltage_limits *tab)
+                                 struct phm_clock_and_voltage_limits *tab)
 {
+       uint32_t vddc, vddci;
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 
        if (tab) {
-               smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, (uint32_t *)&tab->vddc,
-                                                       &data->vddc_leakage);
-               smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, (uint32_t *)&tab->vddci,
-                                                       &data->vddci_leakage);
+               vddc = tab->vddc;
+               smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &vddc,
+                                                  &data->vddc_leakage);
+               tab->vddc = vddc;
+               vddci = tab->vddci;
+               smu7_patch_ppt_v0_with_vdd_leakage(hwmgr, &vddci,
+                                                  &data->vddci_leakage);
+               tab->vddci = vddci;
        }
 
        return 0;
@@ -2968,19 +2984,19 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr,
        if (!(data->mc_micro_code_feature & DISABLE_MC_LOADMICROCODE) && memory_clock > data->highest_mclk)
                data->highest_mclk = memory_clock;
 
-       performance_level = &(ps->performance_levels
-                       [ps->performance_level_count++]);
-
        PP_ASSERT_WITH_CODE(
                        (ps->performance_level_count < smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_GRAPHICS)),
                        "Performance levels exceeds SMC limit!",
                        return -EINVAL);
 
        PP_ASSERT_WITH_CODE(
-                       (ps->performance_level_count <=
+                       (ps->performance_level_count <
                                        hwmgr->platform_descriptor.hardwareActivityPerformanceLevels),
-                       "Performance levels exceeds Driver limit!",
-                       return -EINVAL);
+                       "Performance levels exceeds Driver limit, Skip!",
+                       return 0);
+
+       performance_level = &(ps->performance_levels
+                       [ps->performance_level_count++]);
 
        /* Performance levels are arranged from low to high. */
        performance_level->memory_clock = memory_clock;
@@ -3802,13 +3818,15 @@ static inline bool smu7_are_power_levels_equal(const struct smu7_performance_lev
 
 int smu7_check_states_equal(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *pstate1, const struct pp_hw_power_state *pstate2, bool *equal)
 {
-       const struct smu7_power_state *psa = cast_const_phw_smu7_power_state(pstate1);
-       const struct smu7_power_state *psb = cast_const_phw_smu7_power_state(pstate2);
+       const struct smu7_power_state *psa;
+       const struct smu7_power_state *psb;
        int i;
 
        if (pstate1 == NULL || pstate2 == NULL || equal == NULL)
                return -EINVAL;
 
+       psa = cast_const_phw_smu7_power_state(pstate1);
+       psb = cast_const_phw_smu7_power_state(pstate2);
        /* If the two states don't even have the same number of performance levels they cannot be the same state. */
        if (psa->performance_level_count != psb->performance_level_count) {
                *equal = false;
@@ -4213,18 +4231,26 @@ static int smu7_get_sclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks)
 {
        struct phm_ppt_v1_information *table_info =
                        (struct phm_ppt_v1_information *)hwmgr->pptable;
-       struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table;
+       struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table = NULL;
+       struct phm_clock_voltage_dependency_table *sclk_table;
        int i;
 
-       if (table_info == NULL)
-               return -EINVAL;
-
-       dep_sclk_table = table_info->vdd_dep_on_sclk;
-
-       for (i = 0; i < dep_sclk_table->count; i++) {
-               clocks->clock[i] = dep_sclk_table->entries[i].clk;
-               clocks->count++;
+       if (hwmgr->pp_table_version == PP_TABLE_V1) {
+               if (table_info == NULL || table_info->vdd_dep_on_sclk == NULL)
+                       return -EINVAL;
+               dep_sclk_table = table_info->vdd_dep_on_sclk;
+               for (i = 0; i < dep_sclk_table->count; i++) {
+                       clocks->clock[i] = dep_sclk_table->entries[i].clk;
+                       clocks->count++;
+               }
+       } else if (hwmgr->pp_table_version == PP_TABLE_V0) {
+               sclk_table = hwmgr->dyn_state.vddc_dependency_on_sclk;
+               for (i = 0; i < sclk_table->count; i++) {
+                       clocks->clock[i] = sclk_table->entries[i].clk;
+                       clocks->count++;
+               }
        }
+
        return 0;
 }
 
@@ -4246,17 +4272,24 @@ static int smu7_get_mclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks)
                        (struct phm_ppt_v1_information *)hwmgr->pptable;
        struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table;
        int i;
+       struct phm_clock_voltage_dependency_table *mclk_table;
 
-       if (table_info == NULL)
-               return -EINVAL;
-
-       dep_mclk_table = table_info->vdd_dep_on_mclk;
-
-       for (i = 0; i < dep_mclk_table->count; i++) {
-               clocks->clock[i] = dep_mclk_table->entries[i].clk;
-               clocks->latency[i] = smu7_get_mem_latency(hwmgr,
+       if (hwmgr->pp_table_version == PP_TABLE_V1) {
+               if (table_info == NULL)
+                       return -EINVAL;
+               dep_mclk_table = table_info->vdd_dep_on_mclk;
+               for (i = 0; i < dep_mclk_table->count; i++) {
+                       clocks->clock[i] = dep_mclk_table->entries[i].clk;
+                       clocks->latency[i] = smu7_get_mem_latency(hwmgr,
                                                dep_mclk_table->entries[i].clk);
-               clocks->count++;
+                       clocks->count++;
+               }
+       } else if (hwmgr->pp_table_version == PP_TABLE_V0) {
+               mclk_table = hwmgr->dyn_state.vddc_dependency_on_mclk;
+               for (i = 0; i < mclk_table->count; i++) {
+                       clocks->clock[i] = mclk_table->entries[i].clk;
+                       clocks->count++;
+               }
        }
        return 0;
 }
@@ -4324,6 +4357,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
        .set_mclk_od = smu7_set_mclk_od,
        .get_clock_by_type = smu7_get_clock_by_type,
        .read_sensor = smu7_read_sensor,
+       .dynamic_state_management_disable = smu7_disable_dpm_tasks,
 };
 
 uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
index fb6c6f6106d5fe233e8df5bc1f29cf12385b6b7d..29d0319b22e6c68cfa46466ad13d795a7a7f37cf 100644 (file)
@@ -30,7 +30,7 @@ int smu7_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
                struct phm_fan_speed_info *fan_speed_info)
 {
        if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
+               return -ENODEV;
 
        fan_speed_info->supports_percent_read = true;
        fan_speed_info->supports_percent_write = true;
@@ -60,7 +60,7 @@ int smu7_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
        uint64_t tmp64;
 
        if (hwmgr->thermal_controller.fanInfo.bNoFan)
-               return 0;
+               return -ENODEV;
 
        duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
                        CG_FDO_CTRL1, FMAX_DUTY100);
@@ -89,7 +89,7 @@ int smu7_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
        if (hwmgr->thermal_controller.fanInfo.bNoFan ||
                        (hwmgr->thermal_controller.fanInfo.
                                ucTachometerPulsesPerRevolution == 0))
-               return 0;
+               return -ENODEV;
 
        tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
                        CG_TACH_STATUS, TACH_PERIOD);
index eda802bc63c888ead2082e4362768ba763d1d83f..8c889caba420dc2d55ec9340d46ab0a92d468514 100644 (file)
@@ -2458,7 +2458,7 @@ static int iceland_set_mc_special_registers(struct pp_hwmgr *hwmgr,
                        PP_ASSERT_WITH_CODE((j <= SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE),
                                "Invalid VramInfo table.", return -EINVAL);
 
-                       if (!data->is_memory_gddr5) {
+                       if (!data->is_memory_gddr5 && j < SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE) {
                                table->mc_reg_address[j].s1 = mmMC_PMG_AUTO_CMD;
                                table->mc_reg_address[j].s0 = mmMC_PMG_AUTO_CMD;
                                for (k = 0; k < table->num_entries; k++) {
index 4ccc0b72324de3e6c6e1e530a57f3bb070f92e6d..71bb2f8dc157ba36029c5131237a20a8c0e2b7be 100644 (file)
@@ -2214,6 +2214,7 @@ uint32_t polaris10_get_mac_definition(uint32_t value)
 int polaris10_process_firmware_header(struct pp_hwmgr *hwmgr)
 {
        struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smumgr->backend);
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
        uint32_t tmp;
        int result;
        bool error = false;
@@ -2233,8 +2234,10 @@ int polaris10_process_firmware_header(struct pp_hwmgr *hwmgr)
                        offsetof(SMU74_Firmware_Header, SoftRegisters),
                        &tmp, SMC_RAM_END);
 
-       if (!result)
+       if (!result) {
+               data->soft_regs_start = tmp;
                smu_data->smu7_data.soft_regs_start = tmp;
+       }
 
        error |= (0 != result);
 
index 963a24d46a93d336e2d52bf1f4c7d045c6c2f57e..ffe1f85ce30019dc75b7aff2550ad60c6e70a5f1 100644 (file)
@@ -34,9 +34,6 @@ static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity);
 static void amd_sched_wakeup(struct amd_gpu_scheduler *sched);
 static void amd_sched_process_job(struct fence *f, struct fence_cb *cb);
 
-struct kmem_cache *sched_fence_slab;
-atomic_t sched_fence_slab_ref = ATOMIC_INIT(0);
-
 /* Initialize a given run queue struct */
 static void amd_sched_rq_init(struct amd_sched_rq *rq)
 {
@@ -618,13 +615,6 @@ int amd_sched_init(struct amd_gpu_scheduler *sched,
        INIT_LIST_HEAD(&sched->ring_mirror_list);
        spin_lock_init(&sched->job_list_lock);
        atomic_set(&sched->hw_rq_count, 0);
-       if (atomic_inc_return(&sched_fence_slab_ref) == 1) {
-               sched_fence_slab = kmem_cache_create(
-                       "amd_sched_fence", sizeof(struct amd_sched_fence), 0,
-                       SLAB_HWCACHE_ALIGN, NULL);
-               if (!sched_fence_slab)
-                       return -ENOMEM;
-       }
 
        /* Each scheduler will run on a seperate kernel thread */
        sched->thread = kthread_run(amd_sched_main, sched, sched->name);
@@ -645,6 +635,4 @@ void amd_sched_fini(struct amd_gpu_scheduler *sched)
 {
        if (sched->thread)
                kthread_stop(sched->thread);
-       if (atomic_dec_and_test(&sched_fence_slab_ref))
-               kmem_cache_destroy(sched_fence_slab);
 }
index 7cbbbfb502ef1342caa2a5b36aa970368fed5055..51068e6c3d9af4746e40ebca3f81384e95d5c16c 100644 (file)
@@ -30,9 +30,6 @@
 struct amd_gpu_scheduler;
 struct amd_sched_rq;
 
-extern struct kmem_cache *sched_fence_slab;
-extern atomic_t sched_fence_slab_ref;
-
 /**
  * A scheduler entity is a wrapper around a job queue or a group
  * of other entities. Entities take turns emitting jobs from their
@@ -145,6 +142,9 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
                           struct amd_sched_entity *entity);
 void amd_sched_entity_push_job(struct amd_sched_job *sched_job);
 
+int amd_sched_fence_slab_init(void);
+void amd_sched_fence_slab_fini(void);
+
 struct amd_sched_fence *amd_sched_fence_create(
        struct amd_sched_entity *s_entity, void *owner);
 void amd_sched_fence_scheduled(struct amd_sched_fence *fence);
index 6b63beaf75746848720f98d4eb2b5329c299267b..88fc2d66257990876507b8ab65391ad2a6deca0f 100644 (file)
 #include <drm/drmP.h>
 #include "gpu_scheduler.h"
 
+static struct kmem_cache *sched_fence_slab;
+
+int amd_sched_fence_slab_init(void)
+{
+       sched_fence_slab = kmem_cache_create(
+               "amd_sched_fence", sizeof(struct amd_sched_fence), 0,
+               SLAB_HWCACHE_ALIGN, NULL);
+       if (!sched_fence_slab)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void amd_sched_fence_slab_fini(void)
+{
+       rcu_barrier();
+       kmem_cache_destroy(sched_fence_slab);
+}
+
 struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *entity,
                                               void *owner)
 {
@@ -103,7 +122,7 @@ static void amd_sched_fence_free(struct rcu_head *rcu)
 }
 
 /**
- * amd_sched_fence_release - callback that fence can be freed
+ * amd_sched_fence_release_scheduled - callback that fence can be freed
  *
  * @fence: fence
  *
@@ -118,7 +137,7 @@ static void amd_sched_fence_release_scheduled(struct fence *f)
 }
 
 /**
- * amd_sched_fence_release_scheduled - drop extra reference
+ * amd_sched_fence_release_finished - drop extra reference
  *
  * @f: fence
  *
index b7a8b2ac4055b6594daa4e15d0c68009dd1e1cdc..b69c66b4897e46e2ea77890e39235f3d9e94b57d 100644 (file)
  *
  */
 
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_crtc.h>
 #include <drm/drm_encoder_slave.h>
-#include <drm/drm_atomic_helper.h>
 
 #include "arcpgu.h"
 
-struct arcpgu_drm_connector {
-       struct drm_connector connector;
-       struct drm_encoder_slave *encoder_slave;
-};
-
-static int arcpgu_drm_connector_get_modes(struct drm_connector *connector)
-{
-       const struct drm_encoder_slave_funcs *sfuncs;
-       struct drm_encoder_slave *slave;
-       struct arcpgu_drm_connector *con =
-               container_of(connector, struct arcpgu_drm_connector, connector);
-
-       slave = con->encoder_slave;
-       if (slave == NULL) {
-               dev_err(connector->dev->dev,
-                       "connector_get_modes: cannot find slave encoder for connector\n");
-               return 0;
-       }
-
-       sfuncs = slave->slave_funcs;
-       if (sfuncs->get_modes == NULL)
-               return 0;
-
-       return sfuncs->get_modes(&slave->base, connector);
-}
-
-static enum drm_connector_status
-arcpgu_drm_connector_detect(struct drm_connector *connector, bool force)
-{
-       enum drm_connector_status status = connector_status_unknown;
-       const struct drm_encoder_slave_funcs *sfuncs;
-       struct drm_encoder_slave *slave;
-
-       struct arcpgu_drm_connector *con =
-               container_of(connector, struct arcpgu_drm_connector, connector);
-
-       slave = con->encoder_slave;
-       if (slave == NULL) {
-               dev_err(connector->dev->dev,
-                       "connector_detect: cannot find slave encoder for connector\n");
-               return status;
-       }
-
-       sfuncs = slave->slave_funcs;
-       if (sfuncs && sfuncs->detect)
-               return sfuncs->detect(&slave->base, connector);
-
-       dev_err(connector->dev->dev, "connector_detect: could not detect slave funcs\n");
-       return status;
-}
-
-static void arcpgu_drm_connector_destroy(struct drm_connector *connector)
-{
-       drm_connector_unregister(connector);
-       drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_helper_funcs
-arcpgu_drm_connector_helper_funcs = {
-       .get_modes = arcpgu_drm_connector_get_modes,
-};
-
-static const struct drm_connector_funcs arcpgu_drm_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
-       .reset = drm_atomic_helper_connector_reset,
-       .detect = arcpgu_drm_connector_detect,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .destroy = arcpgu_drm_connector_destroy,
-       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static struct drm_encoder_helper_funcs arcpgu_drm_encoder_helper_funcs = {
-       .dpms = drm_i2c_encoder_dpms,
-       .mode_fixup = drm_i2c_encoder_mode_fixup,
-       .mode_set = drm_i2c_encoder_mode_set,
-       .prepare = drm_i2c_encoder_prepare,
-       .commit = drm_i2c_encoder_commit,
-       .detect = drm_i2c_encoder_detect,
-};
-
 static struct drm_encoder_funcs arcpgu_drm_encoder_funcs = {
        .destroy = drm_encoder_cleanup,
 };
 
 int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np)
 {
-       struct arcpgu_drm_connector *arcpgu_connector;
-       struct drm_i2c_encoder_driver *driver;
-       struct drm_encoder_slave *encoder;
-       struct drm_connector *connector;
-       struct i2c_client *i2c_slave;
-       int ret;
+       struct drm_encoder *encoder;
+       struct drm_bridge *bridge;
+
+       int ret = 0;
 
        encoder = devm_kzalloc(drm->dev, sizeof(*encoder), GFP_KERNEL);
        if (encoder == NULL)
                return -ENOMEM;
 
-       i2c_slave = of_find_i2c_device_by_node(np);
-       if (!i2c_slave || !i2c_get_clientdata(i2c_slave)) {
-               dev_err(drm->dev, "failed to find i2c slave encoder\n");
-               return -EPROBE_DEFER;
-       }
-
-       if (i2c_slave->dev.driver == NULL) {
-               dev_err(drm->dev, "failed to find i2c slave driver\n");
+       /* Locate drm bridge from the hdmi encoder DT node */
+       bridge = of_drm_find_bridge(np);
+       if (!bridge)
                return -EPROBE_DEFER;
-       }
 
-       driver =
-           to_drm_i2c_encoder_driver(to_i2c_driver(i2c_slave->dev.driver));
-       ret = driver->encoder_init(i2c_slave, drm, encoder);
-       if (ret) {
-               dev_err(drm->dev, "failed to initialize i2c encoder slave\n");
-               return ret;
-       }
-
-       encoder->base.possible_crtcs = 1;
-       encoder->base.possible_clones = 0;
-       ret = drm_encoder_init(drm, &encoder->base, &arcpgu_drm_encoder_funcs,
+       encoder->possible_crtcs = 1;
+       encoder->possible_clones = 0;
+       ret = drm_encoder_init(drm, encoder, &arcpgu_drm_encoder_funcs,
                               DRM_MODE_ENCODER_TMDS, NULL);
        if (ret)
                return ret;
 
-       drm_encoder_helper_add(&encoder->base,
-                              &arcpgu_drm_encoder_helper_funcs);
-
-       arcpgu_connector = devm_kzalloc(drm->dev, sizeof(*arcpgu_connector),
-                                       GFP_KERNEL);
-       if (!arcpgu_connector) {
-               ret = -ENOMEM;
-               goto error_encoder_cleanup;
-       }
-
-       connector = &arcpgu_connector->connector;
-       drm_connector_helper_add(connector, &arcpgu_drm_connector_helper_funcs);
-       ret = drm_connector_init(drm, connector, &arcpgu_drm_connector_funcs,
-                       DRM_MODE_CONNECTOR_HDMIA);
-       if (ret < 0) {
-               dev_err(drm->dev, "failed to initialize drm connector\n");
-               goto error_encoder_cleanup;
-       }
+       /* Link drm_bridge to encoder */
+       bridge->encoder = encoder;
+       encoder->bridge = bridge;
 
-       ret = drm_mode_connector_attach_encoder(connector, &encoder->base);
-       if (ret < 0) {
-               dev_err(drm->dev, "could not attach connector to encoder\n");
-               drm_connector_unregister(connector);
-               goto error_connector_cleanup;
-       }
-
-       arcpgu_connector->encoder_slave = encoder;
-
-       return 0;
-
-error_connector_cleanup:
-       drm_connector_cleanup(connector);
+       ret = drm_bridge_attach(drm, bridge);
+       if (ret)
+               drm_encoder_cleanup(encoder);
 
-error_encoder_cleanup:
-       drm_encoder_cleanup(&encoder->base);
        return ret;
 }
index 48019ae22ddba5fcbb3283e94a016543fba3d8b3..28341b32067f89e347c13db6f6a4b97e94022b96 100644 (file)
@@ -150,15 +150,14 @@ static void hdlcd_crtc_enable(struct drm_crtc *crtc)
        clk_prepare_enable(hdlcd->clk);
        hdlcd_crtc_mode_set_nofb(crtc);
        hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
+       drm_crtc_vblank_on(crtc);
 }
 
 static void hdlcd_crtc_disable(struct drm_crtc *crtc)
 {
        struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
 
-       if (!crtc->state->active)
-               return;
-
+       drm_crtc_vblank_off(crtc);
        hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
        clk_disable_unprepare(hdlcd->clk);
 }
index fb6a418ce6be611176e26bf5fa699503178e8364..e138fb51e8ce58e1ac6bad38c96447e68152ec48 100644 (file)
@@ -375,7 +375,6 @@ static int hdlcd_drm_bind(struct device *dev)
 
 err_fbdev:
        drm_kms_helper_poll_fini(drm);
-       drm_mode_config_cleanup(drm);
        drm_vblank_cleanup(drm);
 err_vblank:
        pm_runtime_disable(drm->dev);
@@ -387,6 +386,7 @@ err_unload:
        drm_irq_uninstall(drm);
        of_reserved_mem_device_release(drm->dev);
 err_free:
+       drm_mode_config_cleanup(drm);
        dev_set_drvdata(dev, NULL);
        drm_dev_unref(drm);
 
index 2f58e9e2a59cb4346e339a43953e3ade8941889a..a51f8cbcfe26d9d4d5d52d2037ed94292533c41e 100644 (file)
@@ -332,17 +332,19 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms)
 {
        struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
 
-       if (dcrtc->dpms != dpms) {
-               dcrtc->dpms = dpms;
-               if (!IS_ERR(dcrtc->clk) && !dpms_blanked(dpms))
-                       WARN_ON(clk_prepare_enable(dcrtc->clk));
-               armada_drm_crtc_update(dcrtc);
-               if (!IS_ERR(dcrtc->clk) && dpms_blanked(dpms))
-                       clk_disable_unprepare(dcrtc->clk);
+       if (dpms_blanked(dcrtc->dpms) != dpms_blanked(dpms)) {
                if (dpms_blanked(dpms))
                        armada_drm_vblank_off(dcrtc);
-               else
+               else if (!IS_ERR(dcrtc->clk))
+                       WARN_ON(clk_prepare_enable(dcrtc->clk));
+               dcrtc->dpms = dpms;
+               armada_drm_crtc_update(dcrtc);
+               if (!dpms_blanked(dpms))
                        drm_crtc_vblank_on(&dcrtc->crtc);
+               else if (!IS_ERR(dcrtc->clk))
+                       clk_disable_unprepare(dcrtc->clk);
+       } else if (dcrtc->dpms != dpms) {
+               dcrtc->dpms = dpms;
        }
 }
 
index 608df4c90520278e59bfe75d3c3348d66af51e6c..0743e65cb24020fd7c8dffc679b76f15145b0d97 100644 (file)
@@ -267,6 +267,8 @@ int ast_mm_init(struct ast_private *ast)
                return ret;
        }
 
+       arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
+                                  pci_resource_len(dev->pdev, 0));
        ast->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
                                        pci_resource_len(dev->pdev, 0));
 
@@ -275,11 +277,15 @@ int ast_mm_init(struct ast_private *ast)
 
 void ast_mm_fini(struct ast_private *ast)
 {
+       struct drm_device *dev = ast->dev;
+
        ttm_bo_device_release(&ast->ttm.bdev);
 
        ast_ttm_global_release(ast);
 
        arch_phys_wc_del(ast->fb_mtrr);
+       arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
+                               pci_resource_len(dev->pdev, 0));
 }
 
 void ast_ttm_placement(struct ast_bo *bo, int domain)
index bb2438dd8733f4c2c64618629abf1e946395f02a..5e7e63ce7bcef9bd81058c01e886244e28e15f4a 100644 (file)
@@ -267,6 +267,9 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
                return ret;
        }
 
+       arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
+                                  pci_resource_len(dev->pdev, 0));
+
        cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
                                           pci_resource_len(dev->pdev, 0));
 
@@ -276,6 +279,8 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
 
 void cirrus_mm_fini(struct cirrus_device *cirrus)
 {
+       struct drm_device *dev = cirrus->dev;
+
        if (!cirrus->mm_inited)
                return;
 
@@ -285,6 +290,8 @@ void cirrus_mm_fini(struct cirrus_device *cirrus)
 
        arch_phys_wc_del(cirrus->fb_mtrr);
        cirrus->fb_mtrr = 0;
+       arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
+                               pci_resource_len(dev->pdev, 0));
 }
 
 void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
index 23739609427d86b9cd64d81ddad719bf5fc2bd78..e6862a7442104f59fa476a79a28f48bd0daf98a2 100644 (file)
@@ -420,18 +420,21 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
                                         ssize_t expected_size,
                                         bool *replaced)
 {
-       struct drm_device *dev = crtc->dev;
        struct drm_property_blob *new_blob = NULL;
 
        if (blob_id != 0) {
-               new_blob = drm_property_lookup_blob(dev, blob_id);
+               new_blob = drm_property_lookup_blob(crtc->dev, blob_id);
                if (new_blob == NULL)
                        return -EINVAL;
-               if (expected_size > 0 && expected_size != new_blob->length)
+
+               if (expected_size > 0 && expected_size != new_blob->length) {
+                       drm_property_unreference_blob(new_blob);
                        return -EINVAL;
+               }
        }
 
        drm_atomic_replace_property_blob(blob, new_blob, replaced);
+       drm_property_unreference_blob(new_blob);
 
        return 0;
 }
index c3f83476f99601c2ff91711b602c902b55170f71..21f9926055415e7c0507aa4555e2a3b6daa7ca52 100644 (file)
@@ -594,10 +594,6 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
        struct drm_plane_state *plane_state;
        int i, ret = 0;
 
-       ret = drm_atomic_normalize_zpos(dev, state);
-       if (ret)
-               return ret;
-
        for_each_plane_in_state(state, plane, plane_state, i) {
                const struct drm_plane_helper_funcs *funcs;
 
index 04e457117980b8d554e3561139f52cdc53dedc0d..aa644487749c9cbab104f2ea77c819baf7d6b250 100644 (file)
@@ -914,6 +914,7 @@ static void drm_dp_destroy_port(struct kref *kref)
                /* no need to clean up vcpi
                 * as if we have no connector we never setup a vcpi */
                drm_dp_port_teardown_pdt(port, port->pdt);
+               port->pdt = DP_PEER_DEVICE_NONE;
        }
        kfree(port);
 }
@@ -1159,7 +1160,9 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
                        drm_dp_put_port(port);
                        goto out;
                }
-               if (port->port_num >= DP_MST_LOGICAL_PORT_0) {
+               if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
+                    port->pdt == DP_PEER_DEVICE_SST_SINK) &&
+                   port->port_num >= DP_MST_LOGICAL_PORT_0) {
                        port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
                        drm_mode_connector_set_tile_property(port->connector);
                }
@@ -2919,6 +2922,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
                mgr->cbs->destroy_connector(mgr, port->connector);
 
                drm_dp_port_teardown_pdt(port, port->pdt);
+               port->pdt = DP_PEER_DEVICE_NONE;
 
                if (!port->input && port->vcpi.vcpi > 0) {
                        drm_dp_mst_reset_vcpi_slots(mgr, port);
index 03414bde1f152637a7ed6002ed8a88e30611fec8..6c75e62c0b2254cee15cb88642ed37c1219946c2 100644 (file)
@@ -131,7 +131,12 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
        return 0;
 fail:
        for (i = 0; i < fb_helper->connector_count; i++) {
-               kfree(fb_helper->connector_info[i]);
+               struct drm_fb_helper_connector *fb_helper_connector =
+                       fb_helper->connector_info[i];
+
+               drm_connector_unreference(fb_helper_connector->connector);
+
+               kfree(fb_helper_connector);
                fb_helper->connector_info[i] = NULL;
        }
        fb_helper->connector_count = 0;
@@ -603,6 +608,24 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_blank);
 
+static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
+                                         struct drm_mode_set *modeset)
+{
+       int i;
+
+       for (i = 0; i < modeset->num_connectors; i++) {
+               drm_connector_unreference(modeset->connectors[i]);
+               modeset->connectors[i] = NULL;
+       }
+       modeset->num_connectors = 0;
+
+       drm_mode_destroy(helper->dev, modeset->mode);
+       modeset->mode = NULL;
+
+       /* FIXME should hold a ref? */
+       modeset->fb = NULL;
+}
+
 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
 {
        int i;
@@ -612,10 +635,12 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
                kfree(helper->connector_info[i]);
        }
        kfree(helper->connector_info);
+
        for (i = 0; i < helper->crtc_count; i++) {
-               kfree(helper->crtc_info[i].mode_set.connectors);
-               if (helper->crtc_info[i].mode_set.mode)
-                       drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
+               struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
+
+               drm_fb_helper_modeset_release(helper, modeset);
+               kfree(modeset->connectors);
        }
        kfree(helper->crtc_info);
 }
@@ -644,7 +669,9 @@ static void drm_fb_helper_dirty_work(struct work_struct *work)
        clip->x2 = clip->y2 = 0;
        spin_unlock_irqrestore(&helper->dirty_lock, flags);
 
-       helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
+       /* call dirty callback only when it has been really touched */
+       if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2)
+               helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
 }
 
 /**
@@ -2088,7 +2115,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
        struct drm_fb_helper_crtc **crtcs;
        struct drm_display_mode **modes;
        struct drm_fb_offset *offsets;
-       struct drm_mode_set *modeset;
        bool *enabled;
        int width, height;
        int i;
@@ -2136,45 +2162,35 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 
        /* need to set the modesets up here for use later */
        /* fill out the connector<->crtc mappings into the modesets */
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               modeset = &fb_helper->crtc_info[i].mode_set;
-               modeset->num_connectors = 0;
-               modeset->fb = NULL;
-       }
+       for (i = 0; i < fb_helper->crtc_count; i++)
+               drm_fb_helper_modeset_release(fb_helper,
+                                             &fb_helper->crtc_info[i].mode_set);
 
        for (i = 0; i < fb_helper->connector_count; i++) {
                struct drm_display_mode *mode = modes[i];
                struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
                struct drm_fb_offset *offset = &offsets[i];
-               modeset = &fb_crtc->mode_set;
+               struct drm_mode_set *modeset = &fb_crtc->mode_set;
 
                if (mode && fb_crtc) {
+                       struct drm_connector *connector =
+                               fb_helper->connector_info[i]->connector;
+
                        DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
                                      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
+
                        fb_crtc->desired_mode = mode;
                        fb_crtc->x = offset->x;
                        fb_crtc->y = offset->y;
-                       if (modeset->mode)
-                               drm_mode_destroy(dev, modeset->mode);
                        modeset->mode = drm_mode_duplicate(dev,
                                                           fb_crtc->desired_mode);
-                       modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
+                       drm_connector_reference(connector);
+                       modeset->connectors[modeset->num_connectors++] = connector;
                        modeset->fb = fb_helper->fb;
                        modeset->x = offset->x;
                        modeset->y = offset->y;
                }
        }
-
-       /* Clear out any old modes if there are no more connected outputs. */
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               modeset = &fb_helper->crtc_info[i].mode_set;
-               if (modeset->num_connectors == 0) {
-                       BUG_ON(modeset->fb);
-                       if (modeset->mode)
-                               drm_mode_destroy(dev, modeset->mode);
-                       modeset->mode = NULL;
-               }
-       }
 out:
        kfree(crtcs);
        kfree(modes);
index 1df2d33d0b40ed43e0cbd4623e014851b34ce581..ffb2ab389d1d14863ed1e69c17419d560910afe5 100644 (file)
@@ -54,9 +54,6 @@ int drm_name_info(struct seq_file *m, void *data)
 
        mutex_lock(&dev->master_mutex);
        master = dev->master;
-       if (!master)
-               goto out_unlock;
-
        seq_printf(m, "%s", dev->driver->name);
        if (dev->dev)
                seq_printf(m, " dev=%s", dev_name(dev->dev));
@@ -65,7 +62,6 @@ int drm_name_info(struct seq_file *m, void *data)
        if (dev->unique)
                seq_printf(m, " unique=%s", dev->unique);
        seq_printf(m, "\n");
-out_unlock:
        mutex_unlock(&dev->master_mutex);
 
        return 0;
index 0ad2c47f808fc1d732ef530eba96a6dd265a71c6..71c3473476c7498721a8524c2b8fbde18bf22d7b 100644 (file)
@@ -254,10 +254,12 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
                req->value = dev->mode_config.async_page_flip;
                break;
        case DRM_CAP_PAGE_FLIP_TARGET:
-               req->value = 1;
-               drm_for_each_crtc(crtc, dev) {
-                       if (!crtc->funcs->page_flip_target)
-                               req->value = 0;
+               if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+                       req->value = 1;
+                       drm_for_each_crtc(crtc, dev) {
+                               if (!crtc->funcs->page_flip_target)
+                                       req->value = 0;
+                       }
                }
                break;
        case DRM_CAP_CURSOR_WIDTH:
index cb86c7e5495c58b5a855cede81f20e387d5d6ec0..d9230132dfbcc51d1da070769617b1841ee3a248 100644 (file)
@@ -329,20 +329,34 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
        /*
         * Append a LINK to the submitted command buffer to return to
         * the ring buffer.  return_target is the ring target address.
-        * We need three dwords: event, wait, link.
+        * We need at most 7 dwords in the return target: 2 cache flush +
+        * 2 semaphore stall + 1 event + 1 wait + 1 link.
         */
-       return_dwords = 3;
+       return_dwords = 7;
        return_target = etnaviv_buffer_reserve(gpu, buffer, return_dwords);
        CMD_LINK(cmdbuf, return_dwords, return_target);
 
        /*
-        * Append event, wait and link pointing back to the wait
-        * command to the ring buffer.
+        * Append a cache flush, stall, event, wait and link pointing back to
+        * the wait command to the ring buffer.
         */
+       if (gpu->exec_state == ETNA_PIPE_2D) {
+               CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE,
+                                      VIVS_GL_FLUSH_CACHE_PE2D);
+       } else {
+               CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE,
+                                      VIVS_GL_FLUSH_CACHE_DEPTH |
+                                      VIVS_GL_FLUSH_CACHE_COLOR);
+               CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
+                                      VIVS_TS_FLUSH_CACHE_FLUSH);
+       }
+       CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+       CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
        CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
                       VIVS_GL_EVENT_FROM_PE);
        CMD_WAIT(buffer);
-       CMD_LINK(buffer, 2, return_target + 8);
+       CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) +
+                           buffer->user_size - 4);
 
        if (drm_debug & DRM_UT_DRIVER)
                pr_info("stream link to 0x%08x @ 0x%08x %p\n",
index 5ce3603e6eacb1aab7c59ed66399f743d5346990..0370b842d9cc20c2fdae37406c82a9546106e69b 100644 (file)
@@ -748,19 +748,22 @@ static struct page **etnaviv_gem_userptr_do_get_pages(
        int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
        struct page **pvec;
        uintptr_t ptr;
+       unsigned int flags = 0;
 
        pvec = drm_malloc_ab(npages, sizeof(struct page *));
        if (!pvec)
                return ERR_PTR(-ENOMEM);
 
+       if (!etnaviv_obj->userptr.ro)
+               flags |= FOLL_WRITE;
+
        pinned = 0;
        ptr = etnaviv_obj->userptr.ptr;
 
        down_read(&mm->mmap_sem);
        while (pinned < npages) {
                ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
-                                           !etnaviv_obj->userptr.ro, 0,
-                                           pvec + pinned, NULL);
+                                           flags, pvec + pinned, NULL);
                if (ret < 0)
                        break;
 
index d3796ed8d8c5b2808cd9edba22d5d10a57563917..169ac96e8f0861f9648e0e3ca3292ca1da61556c 100644 (file)
@@ -330,7 +330,8 @@ u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu,
                        return (u32)buf->vram_node.start;
 
                mutex_lock(&mmu->lock);
-               ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node, buf->size);
+               ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node,
+                                             buf->size + SZ_64K);
                if (ret < 0) {
                        mutex_unlock(&mmu->lock);
                        return 0;
index def78c8c1780a90ef8a8354770a3618276a506da..f86e7c8466785caf06c44c625ffd4c44cabae707 100644 (file)
@@ -262,6 +262,26 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
        return 0;
 }
 
+int exynos_atomic_check(struct drm_device *dev,
+                       struct drm_atomic_state *state)
+{
+       int ret;
+
+       ret = drm_atomic_helper_check_modeset(dev, state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_normalize_zpos(dev, state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_helper_check_planes(dev, state);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
 static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_exynos_file_private *file_priv;
index d215149e737b1d19128740f861fb9d83bb7f3606..80c4d5b81689e5a304cd0cc60438adf5b354ad00 100644 (file)
@@ -301,6 +301,7 @@ static inline int exynos_dpi_bind(struct drm_device *dev,
 
 int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
                         bool nonblock);
+int exynos_atomic_check(struct drm_device *dev, struct drm_atomic_state *state);
 
 
 extern struct platform_driver fimd_driver;
index 40ce841eb9529b2f8ce3f3be8049780b64bd91a2..23cce0a3f5fcc842cd708edb594fea9700feec5f 100644 (file)
@@ -190,7 +190,7 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
 static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
        .fb_create = exynos_user_fb_create,
        .output_poll_changed = exynos_drm_output_poll_changed,
-       .atomic_check = drm_atomic_helper_check,
+       .atomic_check = exynos_atomic_check,
        .atomic_commit = exynos_atomic_commit,
 };
 
index aa92decf4233df4a4f06252a85c60ac3a7cd7a37..fbd13fabdf2daf93aeb79cb976c47e467fae6971 100644 (file)
@@ -488,7 +488,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
                goto err_free;
        }
 
-       ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
+       ret = get_vaddr_frames(start, npages, FOLL_FORCE | FOLL_WRITE,
+               g2d_userptr->vec);
        if (ret != npages) {
                DRM_ERROR("failed to get user pages from userptr.\n");
                if (ret < 0)
index e8fb6ef947eea388ac0425054c6ce928bf453a5d..38eaa63afb31f61125314893d154ec03171cb3e1 100644 (file)
@@ -1907,6 +1907,8 @@ err_disable_pm_runtime:
 err_hdmiphy:
        if (hdata->hdmiphy_port)
                put_device(&hdata->hdmiphy_port->dev);
+       if (hdata->regs_hdmiphy)
+               iounmap(hdata->regs_hdmiphy);
 err_ddc:
        put_device(&hdata->ddc_adpt->dev);
 
@@ -1929,6 +1931,9 @@ static int hdmi_remove(struct platform_device *pdev)
        if (hdata->hdmiphy_port)
                put_device(&hdata->hdmiphy_port->dev);
 
+       if (hdata->regs_hdmiphy)
+               iounmap(hdata->regs_hdmiphy);
+
        put_device(&hdata->ddc_adpt->dev);
 
        return 0;
index 3371635cd4d707192e39104ed1bc13671fc19c69..deb57435cc89736e5531e411ef12bcbe8f4d35a1 100644 (file)
 static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc,
                                          struct drm_crtc_state *old_crtc_state)
 {
+       struct drm_device *dev = crtc->dev;
+       struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
        struct drm_pending_vblank_event *event = crtc->state->event;
 
+       regmap_write(fsl_dev->regmap,
+                    DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
+
        if (event) {
                crtc->state->event = NULL;
 
@@ -39,11 +44,15 @@ static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc,
        }
 }
 
-static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
+static void fsl_dcu_drm_crtc_atomic_disable(struct drm_crtc *crtc,
+                                       struct drm_crtc_state *old_crtc_state)
 {
        struct drm_device *dev = crtc->dev;
        struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 
+       /* always disable planes on the CRTC */
+       drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, true);
+
        drm_crtc_vblank_off(crtc);
 
        regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
@@ -51,6 +60,7 @@ static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
                           DCU_MODE_DCU_MODE(DCU_MODE_OFF));
        regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
                     DCU_UPDATE_MODE_READREG);
+       clk_disable_unprepare(fsl_dev->pix_clk);
 }
 
 static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc)
@@ -58,6 +68,7 @@ static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 
+       clk_prepare_enable(fsl_dev->pix_clk);
        regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
                           DCU_MODE_DCU_MODE_MASK,
                           DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
@@ -116,14 +127,12 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
                     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
                     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
                     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
-       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
-                    DCU_UPDATE_MODE_READREG);
        return;
 }
 
 static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = {
+       .atomic_disable = fsl_dcu_drm_crtc_atomic_disable,
        .atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
-       .disable = fsl_dcu_drm_disable_crtc,
        .enable = fsl_dcu_drm_crtc_enable,
        .mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
 };
index 0884c45aefe84a9800b2ec95c57d0f44d1259835..cc2fde2ae5eff272c8f5e15548b61b525a54c6cc 100644 (file)
@@ -59,8 +59,6 @@ static int fsl_dcu_drm_irq_init(struct drm_device *dev)
 
        regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
        regmap_write(fsl_dev->regmap, DCU_INT_MASK, ~0);
-       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
-                    DCU_UPDATE_MODE_READREG);
 
        return ret;
 }
@@ -139,8 +137,6 @@ static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
                drm_handle_vblank(dev, 0);
 
        regmap_write(fsl_dev->regmap, DCU_INT_STATUS, int_status);
-       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
-                    DCU_UPDATE_MODE_READREG);
 
        return IRQ_HANDLED;
 }
@@ -267,12 +263,8 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
                return ret;
        }
 
-       ret = clk_prepare_enable(fsl_dev->pix_clk);
-       if (ret < 0) {
-               dev_err(dev, "failed to enable pix clk\n");
-               goto disable_dcu_clk;
-       }
-
+       if (fsl_dev->tcon)
+               fsl_tcon_bypass_enable(fsl_dev->tcon);
        fsl_dcu_drm_init_planes(fsl_dev->drm);
        drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state);
 
@@ -284,10 +276,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev)
        enable_irq(fsl_dev->irq);
 
        return 0;
-
-disable_dcu_clk:
-       clk_disable_unprepare(fsl_dev->clk);
-       return ret;
 }
 #endif
 
@@ -401,18 +389,12 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
                goto disable_clk;
        }
 
-       ret = clk_prepare_enable(fsl_dev->pix_clk);
-       if (ret < 0) {
-               dev_err(dev, "failed to enable pix clk\n");
-               goto unregister_pix_clk;
-       }
-
        fsl_dev->tcon = fsl_tcon_init(dev);
 
        drm = drm_dev_alloc(driver, dev);
        if (IS_ERR(drm)) {
                ret = PTR_ERR(drm);
-               goto disable_pix_clk;
+               goto unregister_pix_clk;
        }
 
        fsl_dev->dev = dev;
@@ -433,8 +415,6 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev)
 
 unref:
        drm_dev_unref(drm);
-disable_pix_clk:
-       clk_disable_unprepare(fsl_dev->pix_clk);
 unregister_pix_clk:
        clk_unregister(fsl_dev->pix_clk);
 disable_clk:
@@ -447,7 +427,6 @@ static int fsl_dcu_drm_remove(struct platform_device *pdev)
        struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
 
        clk_disable_unprepare(fsl_dev->clk);
-       clk_disable_unprepare(fsl_dev->pix_clk);
        clk_unregister(fsl_dev->pix_clk);
        drm_put_dev(fsl_dev->drm);
 
index a7e5486bd1e934be88374df0ce08731f6286ee1a..a99f4884742058ab6820b8f9cd5e086326caabb5 100644 (file)
@@ -160,11 +160,6 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
                             DCU_LAYER_POST_SKIP(0) |
                             DCU_LAYER_PRE_SKIP(0));
        }
-       regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
-                          DCU_MODE_DCU_MODE_MASK,
-                          DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
-       regmap_write(fsl_dev->regmap,
-                    DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
 
        return;
 }
@@ -211,11 +206,6 @@ void fsl_dcu_drm_init_planes(struct drm_device *dev)
                for (j = 1; j <= fsl_dev->soc->layer_regs; j++)
                        regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0);
        }
-       regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
-                          DCU_MODE_DCU_MODE_MASK,
-                          DCU_MODE_DCU_MODE(DCU_MODE_OFF));
-       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
-                    DCU_UPDATE_MODE_READREG);
 }
 
 struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
index 26edcc899712d16db8959cbb2a5b01c932431c0b..e1dd75b181189bbc27f81eb92ad3f308b735aa2e 100644 (file)
 #include "fsl_dcu_drm_drv.h"
 #include "fsl_tcon.h"
 
-static int
-fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,
-                                struct drm_crtc_state *crtc_state,
-                                struct drm_connector_state *conn_state)
-{
-       return 0;
-}
-
-static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder)
-{
-       struct drm_device *dev = encoder->dev;
-       struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
-
-       if (fsl_dev->tcon)
-               fsl_tcon_bypass_disable(fsl_dev->tcon);
-}
-
-static void fsl_dcu_drm_encoder_enable(struct drm_encoder *encoder)
-{
-       struct drm_device *dev = encoder->dev;
-       struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
-
-       if (fsl_dev->tcon)
-               fsl_tcon_bypass_enable(fsl_dev->tcon);
-}
-
-static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
-       .atomic_check = fsl_dcu_drm_encoder_atomic_check,
-       .disable = fsl_dcu_drm_encoder_disable,
-       .enable = fsl_dcu_drm_encoder_enable,
-};
-
 static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)
 {
        drm_encoder_cleanup(encoder);
@@ -68,13 +36,16 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
        int ret;
 
        encoder->possible_crtcs = 1;
+
+       /* Use bypass mode for parallel RGB/LVDS encoder */
+       if (fsl_dev->tcon)
+               fsl_tcon_bypass_enable(fsl_dev->tcon);
+
        ret = drm_encoder_init(fsl_dev->drm, encoder, &encoder_funcs,
                               DRM_MODE_ENCODER_LVDS, NULL);
        if (ret < 0)
                return ret;
 
-       drm_encoder_helper_add(encoder, &encoder_helper_funcs);
-
        return 0;
 }
 
index bfb2efd8d4d44e996d6af1d75299f12fab534c92..18dfdd5c1b3b1ba5fc8b9c660b37c036d5ea87dd 100644 (file)
@@ -1447,8 +1447,6 @@ static int i915_drm_suspend(struct drm_device *dev)
 
        dev_priv->suspend_count++;
 
-       intel_display_set_init_power(dev_priv, false);
-
        intel_csr_ucode_suspend(dev_priv);
 
 out:
@@ -1466,6 +1464,8 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
 
        disable_rpm_wakeref_asserts(dev_priv);
 
+       intel_display_set_init_power(dev_priv, false);
+
        fw_csr = !IS_BROXTON(dev_priv) &&
                suspend_to_idle(dev_priv) && dev_priv->csr.dmc_payload;
        /*
index 8b9ee4e390c0a1fac6d6449c2ceb2f4f51ca3364..685e9e065287983a50b82aa02faa9822d74d1582 100644 (file)
@@ -2883,6 +2883,11 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
 extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
                              unsigned long arg);
 #endif
+extern const struct dev_pm_ops i915_pm_ops;
+
+extern int i915_driver_load(struct pci_dev *pdev,
+                           const struct pci_device_id *ent);
+extern void i915_driver_unload(struct drm_device *dev);
 extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask);
 extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv);
 extern void i915_reset(struct drm_i915_private *dev_priv);
index 947e82c2b1757993e6b5fff2e6fdf29d4f584ffa..00eb4814b9131655b4ac441d7dbabed02c6ccc8e 100644 (file)
@@ -1806,7 +1806,7 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
                /* Use a partial view if it is bigger than available space */
                chunk_size = MIN_CHUNK_PAGES;
                if (i915_gem_object_is_tiled(obj))
-                       chunk_size = max(chunk_size, tile_row_pages(obj));
+                       chunk_size = roundup(chunk_size, tile_row_pages(obj));
 
                memset(&view, 0, sizeof(view));
                view.type = I915_GGTT_VIEW_PARTIAL;
@@ -2268,7 +2268,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
                        page = shmem_read_mapping_page(mapping, i);
                        if (IS_ERR(page)) {
                                ret = PTR_ERR(page);
-                               goto err_pages;
+                               goto err_sg;
                        }
                }
 #ifdef CONFIG_SWIOTLB
@@ -2311,8 +2311,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 
        return 0;
 
-err_pages:
+err_sg:
        sg_mark_end(sg);
+err_pages:
        for_each_sgt_page(page, sgt_iter, st)
                put_page(page);
        sg_free_table(st);
@@ -3543,15 +3544,27 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
        if (view->type == I915_GGTT_VIEW_NORMAL)
                vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment,
                                               PIN_MAPPABLE | PIN_NONBLOCK);
-       if (IS_ERR(vma))
-               vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment, 0);
+       if (IS_ERR(vma)) {
+               struct drm_i915_private *i915 = to_i915(obj->base.dev);
+               unsigned int flags;
+
+               /* Valleyview is definitely limited to scanning out the first
+                * 512MiB. Lets presume this behaviour was inherited from the
+                * g4x display engine and that all earlier gen are similarly
+                * limited. Testing suggests that it is a little more
+                * complicated than this. For example, Cherryview appears quite
+                * happy to scanout from anywhere within its global aperture.
+                */
+               flags = 0;
+               if (HAS_GMCH_DISPLAY(i915))
+                       flags = PIN_MAPPABLE;
+               vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment, flags);
+       }
        if (IS_ERR(vma))
                goto err_unpin_display;
 
        vma->display_alignment = max_t(u64, vma->display_alignment, alignment);
 
-       WARN_ON(obj->pin_display > i915_vma_pin_count(vma));
-
        i915_gem_object_flush_cpu_write_domain(obj);
 
        old_write_domain = obj->base.write_domain;
@@ -3588,7 +3601,6 @@ i915_gem_object_unpin_from_display_plane(struct i915_vma *vma)
                list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
 
        i915_vma_unpin(vma);
-       WARN_ON(vma->obj->pin_display > i915_vma_pin_count(vma));
 }
 
 /**
@@ -3745,7 +3757,12 @@ void __i915_vma_set_map_and_fenceable(struct i915_vma *vma)
        mappable = (vma->node.start + fence_size <=
                    dev_priv->ggtt.mappable_end);
 
-       if (mappable && fenceable)
+       /*
+        * Explicitly disable for rotated VMA since the display does not
+        * need the fence and the VMA is not accessible to other users.
+        */
+       if (mappable && fenceable &&
+           vma->ggtt_view.type != I915_GGTT_VIEW_ROTATED)
                vma->flags |= I915_VMA_CAN_FENCE;
        else
                vma->flags &= ~I915_VMA_CAN_FENCE;
index 7adb4c77cc7f449698f0207d5f51cbf037cff179..a218c2e395e759e9e3b9c367324311550f4db0a8 100644 (file)
@@ -1281,6 +1281,12 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
        return ctx;
 }
 
+static bool gpu_write_needs_clflush(struct drm_i915_gem_object *obj)
+{
+       return !(obj->cache_level == I915_CACHE_NONE ||
+                obj->cache_level == I915_CACHE_WT);
+}
+
 void i915_vma_move_to_active(struct i915_vma *vma,
                             struct drm_i915_gem_request *req,
                             unsigned int flags)
@@ -1311,6 +1317,8 @@ void i915_vma_move_to_active(struct i915_vma *vma,
 
                /* update for the implicit flush after a batch */
                obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
+               if (!obj->cache_dirty && gpu_write_needs_clflush(obj))
+                       obj->cache_dirty = true;
        }
 
        if (flags & EXEC_OBJECT_NEEDS_FENCE)
index 8df1fa7234e8e031e9c61da4608c5c4b7610476b..2c7ba0ee127c6a230eff6bf7deff705a1259364b 100644 (file)
@@ -290,6 +290,8 @@ i915_vma_put_fence(struct i915_vma *vma)
 {
        struct drm_i915_fence_reg *fence = vma->fence;
 
+       assert_rpm_wakelock_held(to_i915(vma->vm->dev));
+
        if (!fence)
                return 0;
 
@@ -341,6 +343,8 @@ i915_vma_get_fence(struct i915_vma *vma)
        struct drm_i915_fence_reg *fence;
        struct i915_vma *set = i915_gem_object_is_tiled(vma->obj) ? vma : NULL;
 
+       assert_rpm_wakelock_held(to_i915(vma->vm->dev));
+
        /* Just update our place in the LRU if our fence is getting reused. */
        if (vma->fence) {
                fence = vma->fence;
@@ -371,6 +375,12 @@ void i915_gem_restore_fences(struct drm_device *dev)
        struct drm_i915_private *dev_priv = to_i915(dev);
        int i;
 
+       /* Note that this may be called outside of struct_mutex, by
+        * runtime suspend/resume. The barrier we require is enforced by
+        * rpm itself - all access to fences/GTT are only within an rpm
+        * wakeref, and to acquire that wakeref you must pass through here.
+        */
+
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
                struct i915_vma *vma = reg->vma;
@@ -379,10 +389,17 @@ void i915_gem_restore_fences(struct drm_device *dev)
                 * Commit delayed tiling changes if we have an object still
                 * attached to the fence, otherwise just clear the fence.
                 */
-               if (vma && !i915_gem_object_is_tiled(vma->obj))
+               if (vma && !i915_gem_object_is_tiled(vma->obj)) {
+                       GEM_BUG_ON(!reg->dirty);
+                       GEM_BUG_ON(vma->obj->fault_mappable);
+
+                       list_move(&reg->link, &dev_priv->mm.fence_list);
+                       vma->fence = NULL;
                        vma = NULL;
+               }
 
-               fence_update(reg, vma);
+               fence_write(reg, vma);
+               reg->vma = vma;
        }
 }
 
index e537930c64b53d5a18ebbf7fcb79be68f0114acc..c6f780f5abc9cf3776edcfa67a6fa08a6b53239a 100644 (file)
@@ -508,6 +508,10 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
        pvec = drm_malloc_gfp(npages, sizeof(struct page *), GFP_TEMPORARY);
        if (pvec != NULL) {
                struct mm_struct *mm = obj->userptr.mm->mm;
+               unsigned int flags = 0;
+
+               if (!obj->userptr.read_only)
+                       flags |= FOLL_WRITE;
 
                ret = -EFAULT;
                if (atomic_inc_not_zero(&mm->mm_users)) {
@@ -517,7 +521,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
                                        (work->task, mm,
                                         obj->userptr.ptr + pinned * PAGE_SIZE,
                                         npages - pinned,
-                                        !obj->userptr.read_only, 0,
+                                        flags,
                                         pvec + pinned, NULL);
                                if (ret < 0)
                                        break;
index 687c768833b3e4e3d0ef87f4604a5838121d9fdd..31e6edd08dd0525ce9b4477df9e77a3c1ed0c2d5 100644 (file)
@@ -431,9 +431,6 @@ static const struct pci_device_id pciidlist[] = {
 };
 MODULE_DEVICE_TABLE(pci, pciidlist);
 
-extern int i915_driver_load(struct pci_dev *pdev,
-                           const struct pci_device_id *ent);
-
 static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct intel_device_info *intel_info =
@@ -463,8 +460,6 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return i915_driver_load(pdev, ent);
 }
 
-extern void i915_driver_unload(struct drm_device *dev);
-
 static void i915_pci_remove(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
@@ -473,8 +468,6 @@ static void i915_pci_remove(struct pci_dev *pdev)
        drm_dev_unref(dev);
 }
 
-extern const struct dev_pm_ops i915_pm_ops;
-
 static struct pci_driver i915_pci_driver = {
        .name = DRIVER_NAME,
        .id_table = pciidlist,
index c6e69e4cfa8314a051277797bed0ec1fbcceb3ea..cf2560708e031d5957442e60783377ebe4106e11 100644 (file)
@@ -1031,6 +1031,77 @@ static u8 translate_iboost(u8 val)
        return mapping[val];
 }
 
+static void sanitize_ddc_pin(struct drm_i915_private *dev_priv,
+                            enum port port)
+{
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[port];
+       enum port p;
+
+       if (!info->alternate_ddc_pin)
+               return;
+
+       for_each_port_masked(p, (1 << port) - 1) {
+               struct ddi_vbt_port_info *i = &dev_priv->vbt.ddi_port_info[p];
+
+               if (info->alternate_ddc_pin != i->alternate_ddc_pin)
+                       continue;
+
+               DRM_DEBUG_KMS("port %c trying to use the same DDC pin (0x%x) as port %c, "
+                             "disabling port %c DVI/HDMI support\n",
+                             port_name(p), i->alternate_ddc_pin,
+                             port_name(port), port_name(p));
+
+               /*
+                * If we have multiple ports supposedly sharing the
+                * pin, then dvi/hdmi couldn't exist on the shared
+                * port. Otherwise they share the same ddc bin and
+                * system couldn't communicate with them separately.
+                *
+                * Due to parsing the ports in alphabetical order,
+                * a higher port will always clobber a lower one.
+                */
+               i->supports_dvi = false;
+               i->supports_hdmi = false;
+               i->alternate_ddc_pin = 0;
+       }
+}
+
+static void sanitize_aux_ch(struct drm_i915_private *dev_priv,
+                           enum port port)
+{
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[port];
+       enum port p;
+
+       if (!info->alternate_aux_channel)
+               return;
+
+       for_each_port_masked(p, (1 << port) - 1) {
+               struct ddi_vbt_port_info *i = &dev_priv->vbt.ddi_port_info[p];
+
+               if (info->alternate_aux_channel != i->alternate_aux_channel)
+                       continue;
+
+               DRM_DEBUG_KMS("port %c trying to use the same AUX CH (0x%x) as port %c, "
+                             "disabling port %c DP support\n",
+                             port_name(p), i->alternate_aux_channel,
+                             port_name(port), port_name(p));
+
+               /*
+                * If we have multiple ports supposedlt sharing the
+                * aux channel, then DP couldn't exist on the shared
+                * port. Otherwise they share the same aux channel
+                * and system couldn't communicate with them separately.
+                *
+                * Due to parsing the ports in alphabetical order,
+                * a higher port will always clobber a lower one.
+                */
+               i->supports_dp = false;
+               i->alternate_aux_channel = 0;
+       }
+}
+
 static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
                           const struct bdb_header *bdb)
 {
@@ -1072,7 +1143,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
        if (!child)
                return;
 
-       aux_channel = child->raw[25];
+       aux_channel = child->common.aux_channel;
        ddc_pin = child->common.ddc_pin;
 
        is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;
@@ -1105,54 +1176,15 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
                DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port));
 
        if (is_dvi) {
-               if (port == PORT_E) {
-                       info->alternate_ddc_pin = ddc_pin;
-                       /* if DDIE share ddc pin with other port, then
-                        * dvi/hdmi couldn't exist on the shared port.
-                        * Otherwise they share the same ddc bin and system
-                        * couldn't communicate with them seperately. */
-                       if (ddc_pin == DDC_PIN_B) {
-                               dev_priv->vbt.ddi_port_info[PORT_B].supports_dvi = 0;
-                               dev_priv->vbt.ddi_port_info[PORT_B].supports_hdmi = 0;
-                       } else if (ddc_pin == DDC_PIN_C) {
-                               dev_priv->vbt.ddi_port_info[PORT_C].supports_dvi = 0;
-                               dev_priv->vbt.ddi_port_info[PORT_C].supports_hdmi = 0;
-                       } else if (ddc_pin == DDC_PIN_D) {
-                               dev_priv->vbt.ddi_port_info[PORT_D].supports_dvi = 0;
-                               dev_priv->vbt.ddi_port_info[PORT_D].supports_hdmi = 0;
-                       }
-               } else if (ddc_pin == DDC_PIN_B && port != PORT_B)
-                       DRM_DEBUG_KMS("Unexpected DDC pin for port B\n");
-               else if (ddc_pin == DDC_PIN_C && port != PORT_C)
-                       DRM_DEBUG_KMS("Unexpected DDC pin for port C\n");
-               else if (ddc_pin == DDC_PIN_D && port != PORT_D)
-                       DRM_DEBUG_KMS("Unexpected DDC pin for port D\n");
+               info->alternate_ddc_pin = ddc_pin;
+
+               sanitize_ddc_pin(dev_priv, port);
        }
 
        if (is_dp) {
-               if (port == PORT_E) {
-                       info->alternate_aux_channel = aux_channel;
-                       /* if DDIE share aux channel with other port, then
-                        * DP couldn't exist on the shared port. Otherwise
-                        * they share the same aux channel and system
-                        * couldn't communicate with them seperately. */
-                       if (aux_channel == DP_AUX_A)
-                               dev_priv->vbt.ddi_port_info[PORT_A].supports_dp = 0;
-                       else if (aux_channel == DP_AUX_B)
-                               dev_priv->vbt.ddi_port_info[PORT_B].supports_dp = 0;
-                       else if (aux_channel == DP_AUX_C)
-                               dev_priv->vbt.ddi_port_info[PORT_C].supports_dp = 0;
-                       else if (aux_channel == DP_AUX_D)
-                               dev_priv->vbt.ddi_port_info[PORT_D].supports_dp = 0;
-               }
-               else if (aux_channel == DP_AUX_A && port != PORT_A)
-                       DRM_DEBUG_KMS("Unexpected AUX channel for port A\n");
-               else if (aux_channel == DP_AUX_B && port != PORT_B)
-                       DRM_DEBUG_KMS("Unexpected AUX channel for port B\n");
-               else if (aux_channel == DP_AUX_C && port != PORT_C)
-                       DRM_DEBUG_KMS("Unexpected AUX channel for port C\n");
-               else if (aux_channel == DP_AUX_D && port != PORT_D)
-                       DRM_DEBUG_KMS("Unexpected AUX channel for port D\n");
+               info->alternate_aux_channel = aux_channel;
+
+               sanitize_aux_ch(dev_priv, port);
        }
 
        if (bdb->version >= 158) {
@@ -1641,7 +1673,8 @@ bool intel_bios_is_port_edp(struct drm_i915_private *dev_priv, enum port port)
        return false;
 }
 
-bool intel_bios_is_port_dp_dual_mode(struct drm_i915_private *dev_priv, enum port port)
+static bool child_dev_is_dp_dual_mode(const union child_device_config *p_child,
+                                     enum port port)
 {
        static const struct {
                u16 dp, hdmi;
@@ -1655,22 +1688,35 @@ bool intel_bios_is_port_dp_dual_mode(struct drm_i915_private *dev_priv, enum por
                [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, },
                [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, },
        };
-       int i;
 
        if (port == PORT_A || port >= ARRAY_SIZE(port_mapping))
                return false;
 
-       if (!dev_priv->vbt.child_dev_num)
+       if ((p_child->common.device_type & DEVICE_TYPE_DP_DUAL_MODE_BITS) !=
+           (DEVICE_TYPE_DP_DUAL_MODE & DEVICE_TYPE_DP_DUAL_MODE_BITS))
                return false;
 
+       if (p_child->common.dvo_port == port_mapping[port].dp)
+               return true;
+
+       /* Only accept a HDMI dvo_port as DP++ if it has an AUX channel */
+       if (p_child->common.dvo_port == port_mapping[port].hdmi &&
+           p_child->common.aux_channel != 0)
+               return true;
+
+       return false;
+}
+
+bool intel_bios_is_port_dp_dual_mode(struct drm_i915_private *dev_priv,
+                                    enum port port)
+{
+       int i;
+
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
                const union child_device_config *p_child =
                        &dev_priv->vbt.child_dev[i];
 
-               if ((p_child->common.dvo_port == port_mapping[port].dp ||
-                    p_child->common.dvo_port == port_mapping[port].hdmi) &&
-                   (p_child->common.device_type & DEVICE_TYPE_DP_DUAL_MODE_BITS) ==
-                   (DEVICE_TYPE_DP_DUAL_MODE & DEVICE_TYPE_DP_DUAL_MODE_BITS))
+               if (child_dev_is_dp_dual_mode(p_child, port))
                        return true;
        }
 
index 73b6858600acf56b30ef75e62c9a63804ed305e3..1b20e160bc1f68f0819cc4875c23d00a117d51d2 100644 (file)
@@ -192,7 +192,7 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
        struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
        const int s_max = 3, ss_max = 3, eu_max = 8;
        int s, ss;
-       u32 fuse2, eu_disable[s_max];
+       u32 fuse2, eu_disable[3]; /* s_max */
 
        fuse2 = I915_READ(GEN8_FUSE2);
        sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
index fbcfed63a76e16ec59f465c96e9b5c7c8d37ffe2..3cb70d73239bf424857c87d3dbc252cfa94c37ab 100644 (file)
@@ -2978,7 +2978,8 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
        /* Rotate src coordinates to match rotated GTT view */
        if (intel_rotation_90_or_270(rotation))
                drm_rect_rotate(&plane_state->base.src,
-                               fb->width, fb->height, DRM_ROTATE_270);
+                               fb->width << 16, fb->height << 16,
+                               DRM_ROTATE_270);
 
        /*
         * Handle the AUX surface first since
@@ -10242,6 +10243,29 @@ static void bxt_modeset_commit_cdclk(struct drm_atomic_state *old_state)
        bxt_set_cdclk(to_i915(dev), req_cdclk);
 }
 
+static int bdw_adjust_min_pipe_pixel_rate(struct intel_crtc_state *crtc_state,
+                                         int pixel_rate)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+
+       /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
+       if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled)
+               pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95);
+
+       /* BSpec says "Do not use DisplayPort with CDCLK less than
+        * 432 MHz, audio enabled, port width x4, and link rate
+        * HBR2 (5.4 GHz), or else there may be audio corruption or
+        * screen corruption."
+        */
+       if (intel_crtc_has_dp_encoder(crtc_state) &&
+           crtc_state->has_audio &&
+           crtc_state->port_clock >= 540000 &&
+           crtc_state->lane_count == 4)
+               pixel_rate = max(432000, pixel_rate);
+
+       return pixel_rate;
+}
+
 /* compute the max rate for new configuration */
 static int ilk_max_pixel_rate(struct drm_atomic_state *state)
 {
@@ -10267,9 +10291,9 @@ static int ilk_max_pixel_rate(struct drm_atomic_state *state)
 
                pixel_rate = ilk_pipe_pixel_rate(crtc_state);
 
-               /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
-               if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled)
-                       pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95);
+               if (IS_BROADWELL(dev_priv) || IS_GEN9(dev_priv))
+                       pixel_rate = bdw_adjust_min_pipe_pixel_rate(crtc_state,
+                                                                   pixel_rate);
 
                intel_state->min_pixclk[i] = pixel_rate;
        }
@@ -12236,7 +12260,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        intel_crtc->reset_count = i915_reset_count(&dev_priv->gpu_error);
        if (i915_reset_in_progress_or_wedged(&dev_priv->gpu_error)) {
                ret = -EIO;
-               goto cleanup;
+               goto unlock;
        }
 
        atomic_inc(&intel_crtc->unpin_work_count);
@@ -12328,6 +12352,7 @@ cleanup_unpin:
        intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
 cleanup_pending:
        atomic_dec(&intel_crtc->unpin_work_count);
+unlock:
        mutex_unlock(&dev->struct_mutex);
 cleanup:
        crtc->primary->fb = old_fb;
@@ -14310,7 +14335,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 
        for_each_plane_in_state(state, plane, plane_state, i) {
                struct intel_plane_state *intel_plane_state =
-                       to_intel_plane_state(plane_state);
+                       to_intel_plane_state(plane->state);
 
                if (!intel_plane_state->wait_req)
                        continue;
index 14a3cf0b72133a2734cb98059fbdd524578dc392..bf344d08356a2b48a77726fa8bf749c55eb2651f 100644 (file)
@@ -1108,6 +1108,44 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        return ret;
 }
 
+static enum port intel_aux_port(struct drm_i915_private *dev_priv,
+                               enum port port)
+{
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[port];
+       enum port aux_port;
+
+       if (!info->alternate_aux_channel) {
+               DRM_DEBUG_KMS("using AUX %c for port %c (platform default)\n",
+                             port_name(port), port_name(port));
+               return port;
+       }
+
+       switch (info->alternate_aux_channel) {
+       case DP_AUX_A:
+               aux_port = PORT_A;
+               break;
+       case DP_AUX_B:
+               aux_port = PORT_B;
+               break;
+       case DP_AUX_C:
+               aux_port = PORT_C;
+               break;
+       case DP_AUX_D:
+               aux_port = PORT_D;
+               break;
+       default:
+               MISSING_CASE(info->alternate_aux_channel);
+               aux_port = PORT_A;
+               break;
+       }
+
+       DRM_DEBUG_KMS("using AUX %c for port %c (VBT)\n",
+                     port_name(aux_port), port_name(port));
+
+       return aux_port;
+}
+
 static i915_reg_t g4x_aux_ctl_reg(struct drm_i915_private *dev_priv,
                                       enum port port)
 {
@@ -1168,36 +1206,9 @@ static i915_reg_t ilk_aux_data_reg(struct drm_i915_private *dev_priv,
        }
 }
 
-/*
- * On SKL we don't have Aux for port E so we rely
- * on VBT to set a proper alternate aux channel.
- */
-static enum port skl_porte_aux_port(struct drm_i915_private *dev_priv)
-{
-       const struct ddi_vbt_port_info *info =
-               &dev_priv->vbt.ddi_port_info[PORT_E];
-
-       switch (info->alternate_aux_channel) {
-       case DP_AUX_A:
-               return PORT_A;
-       case DP_AUX_B:
-               return PORT_B;
-       case DP_AUX_C:
-               return PORT_C;
-       case DP_AUX_D:
-               return PORT_D;
-       default:
-               MISSING_CASE(info->alternate_aux_channel);
-               return PORT_A;
-       }
-}
-
 static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv,
                                       enum port port)
 {
-       if (port == PORT_E)
-               port = skl_porte_aux_port(dev_priv);
-
        switch (port) {
        case PORT_A:
        case PORT_B:
@@ -1213,9 +1224,6 @@ static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv,
 static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv,
                                        enum port port, int index)
 {
-       if (port == PORT_E)
-               port = skl_porte_aux_port(dev_priv);
-
        switch (port) {
        case PORT_A:
        case PORT_B:
@@ -1253,7 +1261,8 @@ static i915_reg_t intel_aux_data_reg(struct drm_i915_private *dev_priv,
 static void intel_aux_reg_init(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
-       enum port port = dp_to_dig_port(intel_dp)->port;
+       enum port port = intel_aux_port(dev_priv,
+                                       dp_to_dig_port(intel_dp)->port);
        int i;
 
        intel_dp->aux_ch_ctl_reg = intel_aux_ctl_reg(dev_priv, port);
@@ -3551,8 +3560,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
        /* Read the eDP Display control capabilities registers */
        if ((intel_dp->dpcd[DP_EDP_CONFIGURATION_CAP] & DP_DPCD_DISPLAY_CONTROL_CAPABLE) &&
            drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
-                            intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd) ==
-                            sizeof(intel_dp->edp_dpcd)))
+                            intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) ==
+                            sizeof(intel_dp->edp_dpcd))
                DRM_DEBUG_KMS("EDP DPCD : %*ph\n", (int) sizeof(intel_dp->edp_dpcd),
                              intel_dp->edp_dpcd);
 
@@ -4454,21 +4463,11 @@ static enum drm_connector_status
 intel_dp_detect(struct drm_connector *connector, bool force)
 {
        struct intel_dp *intel_dp = intel_attached_dp(connector);
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        enum drm_connector_status status = connector->status;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
 
-       if (intel_dp->is_mst) {
-               /* MST devices are disconnected from a monitor POV */
-               intel_dp_unset_edid(intel_dp);
-               if (intel_encoder->type != INTEL_OUTPUT_EDP)
-                       intel_encoder->type = INTEL_OUTPUT_DP;
-               return connector_status_disconnected;
-       }
-
        /* If full detect is not performed yet, do a full detect */
        if (!intel_dp->detect_done)
                status = intel_dp_long_pulse(intel_dp->attached_connector);
index faa67624e1ed734b80b0c0b9734b63c173d9389c..c43dd9abce790cf797804bde73781363c396d91d 100644 (file)
@@ -104,8 +104,10 @@ static int intel_fbc_calculate_cfb_size(struct drm_i915_private *dev_priv,
        int lines;
 
        intel_fbc_get_plane_source_size(cache, NULL, &lines);
-       if (INTEL_INFO(dev_priv)->gen >= 7)
+       if (INTEL_GEN(dev_priv) == 7)
                lines = min(lines, 2048);
+       else if (INTEL_GEN(dev_priv) >= 8)
+               lines = min(lines, 2560);
 
        /* Hardware needs the full buffer stride, not just the active area. */
        return lines * cache->fb.stride;
index f40a35f2913a8222f2800bfa081b3adb1c636288..13c306173f27b9be7dde7e831d1dca942b59a4e0 100644 (file)
@@ -1799,6 +1799,50 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
        intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
 }
 
+static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
+                            enum port port)
+{
+       const struct ddi_vbt_port_info *info =
+               &dev_priv->vbt.ddi_port_info[port];
+       u8 ddc_pin;
+
+       if (info->alternate_ddc_pin) {
+               DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (VBT)\n",
+                             info->alternate_ddc_pin, port_name(port));
+               return info->alternate_ddc_pin;
+       }
+
+       switch (port) {
+       case PORT_B:
+               if (IS_BROXTON(dev_priv))
+                       ddc_pin = GMBUS_PIN_1_BXT;
+               else
+                       ddc_pin = GMBUS_PIN_DPB;
+               break;
+       case PORT_C:
+               if (IS_BROXTON(dev_priv))
+                       ddc_pin = GMBUS_PIN_2_BXT;
+               else
+                       ddc_pin = GMBUS_PIN_DPC;
+               break;
+       case PORT_D:
+               if (IS_CHERRYVIEW(dev_priv))
+                       ddc_pin = GMBUS_PIN_DPD_CHV;
+               else
+                       ddc_pin = GMBUS_PIN_DPD;
+               break;
+       default:
+               MISSING_CASE(port);
+               ddc_pin = GMBUS_PIN_DPB;
+               break;
+       }
+
+       DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (platform default)\n",
+                     ddc_pin, port_name(port));
+
+       return ddc_pin;
+}
+
 void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
                               struct intel_connector *intel_connector)
 {
@@ -1808,7 +1852,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        enum port port = intel_dig_port->port;
-       uint8_t alternate_ddc_pin;
 
        DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
                      port_name(port));
@@ -1826,12 +1869,10 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
        connector->doublescan_allowed = 0;
        connector->stereo_allowed = 1;
 
+       intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(dev_priv, port);
+
        switch (port) {
        case PORT_B:
-               if (IS_BROXTON(dev_priv))
-                       intel_hdmi->ddc_bus = GMBUS_PIN_1_BXT;
-               else
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DPB;
                /*
                 * On BXT A0/A1, sw needs to activate DDIA HPD logic and
                 * interrupts to check the external panel connection.
@@ -1842,46 +1883,17 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
                        intel_encoder->hpd_pin = HPD_PORT_B;
                break;
        case PORT_C:
-               if (IS_BROXTON(dev_priv))
-                       intel_hdmi->ddc_bus = GMBUS_PIN_2_BXT;
-               else
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DPC;
                intel_encoder->hpd_pin = HPD_PORT_C;
                break;
        case PORT_D:
-               if (WARN_ON(IS_BROXTON(dev_priv)))
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DISABLED;
-               else if (IS_CHERRYVIEW(dev_priv))
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DPD_CHV;
-               else
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DPD;
                intel_encoder->hpd_pin = HPD_PORT_D;
                break;
        case PORT_E:
-               /* On SKL PORT E doesn't have seperate GMBUS pin
-                *  We rely on VBT to set a proper alternate GMBUS pin. */
-               alternate_ddc_pin =
-                       dev_priv->vbt.ddi_port_info[PORT_E].alternate_ddc_pin;
-               switch (alternate_ddc_pin) {
-               case DDC_PIN_B:
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DPB;
-                       break;
-               case DDC_PIN_C:
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DPC;
-                       break;
-               case DDC_PIN_D:
-                       intel_hdmi->ddc_bus = GMBUS_PIN_DPD;
-                       break;
-               default:
-                       MISSING_CASE(alternate_ddc_pin);
-               }
                intel_encoder->hpd_pin = HPD_PORT_E;
                break;
-       case PORT_A:
-               intel_encoder->hpd_pin = HPD_PORT_A;
-               /* Internal port only for eDP. */
        default:
-               BUG();
+               MISSING_CASE(port);
+               return;
        }
 
        if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
index a2f751cd187a2fe2d8552758b71326439aa205de..db24f898853cbbbc98d2043b9a511956dd0bc1bd 100644 (file)
@@ -3362,13 +3362,15 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
        int num_active;
        int id, i;
 
+       /* Clear the partitioning for disabled planes. */
+       memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
+       memset(ddb->y_plane[pipe], 0, sizeof(ddb->y_plane[pipe]));
+
        if (WARN_ON(!state))
                return 0;
 
        if (!cstate->base.active) {
                ddb->pipe[pipe].start = ddb->pipe[pipe].end = 0;
-               memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
-               memset(ddb->y_plane[pipe], 0, sizeof(ddb->y_plane[pipe]));
                return 0;
        }
 
@@ -3468,12 +3470,6 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
        return 0;
 }
 
-static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_state *config)
-{
-       /* TODO: Take into account the scalers once we support them */
-       return config->base.adjusted_mode.crtc_clock;
-}
-
 /*
  * The max latency should be 257 (max the punit can code is 255 and we add 2us
  * for the read latency) and cpp should always be <= 8, so that
@@ -3524,7 +3520,7 @@ static uint32_t skl_adjusted_plane_pixel_rate(const struct intel_crtc_state *cst
         * Adjusted plane pixel rate is just the pipe's adjusted pixel rate
         * with additional adjustments for plane-specific scaling.
         */
-       adjusted_pixel_rate = skl_pipe_pixel_rate(cstate);
+       adjusted_pixel_rate = ilk_pipe_pixel_rate(cstate);
        downscale_amount = skl_plane_downscale_amount(pstate);
 
        pixel_rate = adjusted_pixel_rate * downscale_amount >> 16;
@@ -3736,11 +3732,11 @@ skl_compute_linetime_wm(struct intel_crtc_state *cstate)
        if (!cstate->base.active)
                return 0;
 
-       if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0))
+       if (WARN_ON(ilk_pipe_pixel_rate(cstate) == 0))
                return 0;
 
        return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000,
-                           skl_pipe_pixel_rate(cstate));
+                           ilk_pipe_pixel_rate(cstate));
 }
 
 static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
@@ -4050,6 +4046,12 @@ skl_compute_ddb(struct drm_atomic_state *state)
                intel_state->wm_results.dirty_pipes = ~0;
        }
 
+       /*
+        * We're not recomputing for the pipes not included in the commit, so
+        * make sure we start with the current state.
+        */
+       memcpy(ddb, &dev_priv->wm.skl_hw.ddb, sizeof(*ddb));
+
        for_each_intel_crtc_mask(dev, intel_crtc, realloc_pipes) {
                struct intel_crtc_state *cstate;
 
index 6c11168facd63c7fd18eeb64e49abfa283e9c87a..a38c2fefe85a6fc2abb1fcaabe2143da3c95be3a 100644 (file)
@@ -1139,7 +1139,9 @@ static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)
 
        intel_power_sequencer_reset(dev_priv);
 
-       intel_hpd_poll_init(dev_priv);
+       /* Prevent us from re-enabling polling on accident in late suspend */
+       if (!dev_priv->drm.dev->power.is_suspended)
+               intel_hpd_poll_init(dev_priv);
 }
 
 static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
index 73a521fdf1bdf760e7d487f0e632b80020e43e49..dbed12c484c9d5d5f3af0529caa4746737f4b007 100644 (file)
@@ -358,7 +358,7 @@ vlv_update_plane(struct drm_plane *dplane,
        int plane = intel_plane->plane;
        u32 sprctl;
        u32 sprsurf_offset, linear_offset;
-       unsigned int rotation = dplane->state->rotation;
+       unsigned int rotation = plane_state->base.rotation;
        const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
        int crtc_x = plane_state->base.dst.x1;
        int crtc_y = plane_state->base.dst.y1;
index 68db9621f1f0db0dcdbd715d14c02715c19b5b95..8886cab19f985abf7e70451c991a5a84c9a60adf 100644 (file)
@@ -280,7 +280,8 @@ struct common_child_dev_config {
        u8 dp_support:1;
        u8 tmds_support:1;
        u8 support_reserved:5;
-       u8 not_common3[12];
+       u8 aux_channel;
+       u8 not_common3[11];
        u8 iboost_level;
 } __packed;
 
index 98df09c2b3885b0ad0e5d99434063005a11f6712..9672b579f9506942fa1a697b4708737edc8ad7a0 100644 (file)
@@ -357,8 +357,8 @@ static int imx_drm_bind(struct device *dev)
        int ret;
 
        drm = drm_dev_alloc(&imx_drm_driver, dev);
-       if (!drm)
-               return -ENOMEM;
+       if (IS_ERR(drm))
+               return PTR_ERR(drm);
 
        imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
        if (!imxdrm) {
@@ -436,9 +436,11 @@ static int imx_drm_bind(struct device *dev)
 
 err_fbhelper:
        drm_kms_helper_poll_fini(drm);
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
        if (imxdrm->fbhelper)
                drm_fbdev_cma_fini(imxdrm->fbhelper);
 err_unbind:
+#endif
        component_unbind_all(drm->dev, drm);
 err_vblank:
        drm_vblank_cleanup(drm);
index 4e1ae3fc462dc65591d2fa5b3f6dffe3ee8a4ad4..6be515a9fb694b5fdac53d880430ba218b08e544 100644 (file)
@@ -68,6 +68,12 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
 
        ipu_dc_disable_channel(ipu_crtc->dc);
        ipu_di_disable(ipu_crtc->di);
+       /*
+        * Planes must be disabled before DC clock is removed, as otherwise the
+        * attached IDMACs will be left in undefined state, possibly hanging
+        * the IPU or even system.
+        */
+       drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
        ipu_dc_disable(ipu);
 
        spin_lock_irq(&crtc->dev->event_lock);
@@ -77,9 +83,6 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
        }
        spin_unlock_irq(&crtc->dev->event_lock);
 
-       /* always disable planes on the CRTC */
-       drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, true);
-
        drm_crtc_vblank_off(crtc);
 }
 
index ce22d0a0ddc8116e8026571f7bd700f461f5ee08..d5864ed4d772fdd2f4d5dfd0be9a13e372e27569 100644 (file)
@@ -103,11 +103,11 @@ drm_plane_state_to_vbo(struct drm_plane_state *state)
               (state->src_x >> 16) / 2 - eba;
 }
 
-static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane,
-                                     struct drm_plane_state *old_state)
+static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane)
 {
        struct drm_plane *plane = &ipu_plane->base;
        struct drm_plane_state *state = plane->state;
+       struct drm_crtc_state *crtc_state = state->crtc->state;
        struct drm_framebuffer *fb = state->fb;
        unsigned long eba, ubo, vbo;
        int active;
@@ -117,7 +117,7 @@ static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane,
        switch (fb->pixel_format) {
        case DRM_FORMAT_YUV420:
        case DRM_FORMAT_YVU420:
-               if (old_state->fb)
+               if (!drm_atomic_crtc_needs_modeset(crtc_state))
                        break;
 
                /*
@@ -149,7 +149,7 @@ static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane,
                break;
        }
 
-       if (old_state->fb) {
+       if (!drm_atomic_crtc_needs_modeset(crtc_state)) {
                active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
                ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
                ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
@@ -259,6 +259,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
        struct drm_framebuffer *fb = state->fb;
        struct drm_framebuffer *old_fb = old_state->fb;
        unsigned long eba, ubo, vbo, old_ubo, old_vbo;
+       int hsub, vsub;
 
        /* Ok to disable */
        if (!fb)
@@ -355,7 +356,9 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
                if ((ubo > 0xfffff8) || (vbo > 0xfffff8))
                        return -EINVAL;
 
-               if (old_fb) {
+               if (old_fb &&
+                   (old_fb->pixel_format == DRM_FORMAT_YUV420 ||
+                    old_fb->pixel_format == DRM_FORMAT_YVU420)) {
                        old_ubo = drm_plane_state_to_ubo(old_state);
                        old_vbo = drm_plane_state_to_vbo(old_state);
                        if (ubo != old_ubo || vbo != old_vbo)
@@ -370,6 +373,16 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
 
                if (old_fb && old_fb->pitches[1] != fb->pitches[1])
                        crtc_state->mode_changed = true;
+
+               /*
+                * The x/y offsets must be even in case of horizontal/vertical
+                * chroma subsampling.
+                */
+               hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
+               vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
+               if (((state->src_x >> 16) & (hsub - 1)) ||
+                   ((state->src_y >> 16) & (vsub - 1)))
+                       return -EINVAL;
        }
 
        return 0;
@@ -392,7 +405,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
                struct drm_crtc_state *crtc_state = state->crtc->state;
 
                if (!drm_atomic_crtc_needs_modeset(crtc_state)) {
-                       ipu_plane_atomic_set_base(ipu_plane, old_state);
+                       ipu_plane_atomic_set_base(ipu_plane);
                        return;
                }
        }
@@ -424,6 +437,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
                        ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
                        break;
                default:
+                       ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
                        break;
                }
        }
@@ -437,7 +451,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
        ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
        ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
        ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
-       ipu_plane_atomic_set_base(ipu_plane, old_state);
+       ipu_plane_atomic_set_base(ipu_plane);
        ipu_plane_enable(ipu_plane);
 }
 
index 019b7ca392d7a49db0ffcb25ccb36f293f9d530e..c70310206ac56fd76eeb93ae76af669f1f2870a7 100644 (file)
@@ -80,6 +80,7 @@ static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp,
                                                 ddp_comp);
 
        priv->crtc = crtc;
+       writel(0x0, comp->regs + DISP_REG_OVL_INTSTA);
        writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN);
 }
 
@@ -250,13 +251,6 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
-                              IRQF_TRIGGER_NONE, dev_name(dev), priv);
-       if (ret < 0) {
-               dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
-               return ret;
-       }
-
        comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_OVL);
        if (comp_id < 0) {
                dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
@@ -272,6 +266,13 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, priv);
 
+       ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
+                              IRQF_TRIGGER_NONE, dev_name(dev), priv);
+       if (ret < 0) {
+               dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
+               return ret;
+       }
+
        ret = component_add(dev, &mtk_disp_ovl_component_ops);
        if (ret)
                dev_err(dev, "Failed to add component: %d\n", ret);
index 0186e500d2a544d8c90769428c7673bec1cd68c0..90fb831ef031b9794df4f1ef95609204bedce93a 100644 (file)
@@ -432,11 +432,16 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
        unsigned long pll_rate;
        unsigned int factor;
 
+       /* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */
        pix_rate = 1000UL * mode->clock;
-       if (mode->clock <= 74000)
+       if (mode->clock <= 27000)
+               factor = 16 * 3;
+       else if (mode->clock <= 84000)
                factor = 8 * 3;
-       else
+       else if (mode->clock <= 167000)
                factor = 4 * 3;
+       else
+               factor = 2 * 3;
        pll_rate = pix_rate * factor;
 
        dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
index df33b3ca6ffd5b2038e3e01d81ada28ffd33462e..48cc01fd20c78db1533ff8da0edf6c76e7f163e4 100644 (file)
@@ -123,7 +123,7 @@ static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
                          unsigned int bpc)
 {
        writel(w << 16 | h, comp->regs + DISP_OD_SIZE);
-       writel(OD_RELAYMODE, comp->regs + OD_RELAYMODE);
+       writel(OD_RELAYMODE, comp->regs + DISP_OD_CFG);
        mtk_dither_set(comp, bpc, DISP_OD_CFG);
 }
 
index 28b2044ed9f285ad7c1bf1441822c3bcd24d9196..eaa5a2240c0c9db36b3ca918e589e117aee01077 100644 (file)
@@ -86,7 +86,7 @@
 
 #define DSI_PHY_TIMECON0       0x110
 #define LPX                            (0xff << 0)
-#define HS_PRPR                                (0xff << 8)
+#define HS_PREP                                (0xff << 8)
 #define HS_ZERO                                (0xff << 16)
 #define HS_TRAIL                       (0xff << 24)
 
 #define CLK_TRAIL                      (0xff << 24)
 
 #define DSI_PHY_TIMECON3       0x11c
-#define CLK_HS_PRPR                    (0xff << 0)
+#define CLK_HS_PREP                    (0xff << 0)
 #define CLK_HS_POST                    (0xff << 8)
 #define CLK_HS_EXIT                    (0xff << 16)
 
+#define T_LPX          5
+#define T_HS_PREP      6
+#define T_HS_TRAIL     8
+#define T_HS_EXIT      7
+#define T_HS_ZERO      10
+
 #define NS_TO_CYCLE(n, c)    ((n) / (c) + (((n) % (c)) ? 1 : 0))
 
 struct phy;
@@ -161,20 +167,18 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data)
 static void dsi_phy_timconfig(struct mtk_dsi *dsi)
 {
        u32 timcon0, timcon1, timcon2, timcon3;
-       unsigned int ui, cycle_time;
-       unsigned int lpx;
+       u32 ui, cycle_time;
 
        ui = 1000 / dsi->data_rate + 0x01;
        cycle_time = 8000 / dsi->data_rate + 0x01;
-       lpx = 5;
 
-       timcon0 = (8 << 24) | (0xa << 16) | (0x6 << 8) | lpx;
-       timcon1 = (7 << 24) | (5 * lpx << 16) | ((3 * lpx) / 2) << 8 |
-                 (4 * lpx);
+       timcon0 = T_LPX | T_HS_PREP << 8 | T_HS_ZERO << 16 | T_HS_TRAIL << 24;
+       timcon1 = 4 * T_LPX | (3 * T_LPX / 2) << 8 | 5 * T_LPX << 16 |
+                 T_HS_EXIT << 24;
        timcon2 = ((NS_TO_CYCLE(0x64, cycle_time) + 0xa) << 24) |
                  (NS_TO_CYCLE(0x150, cycle_time) << 16);
-       timcon3 = (2 * lpx) << 16 | NS_TO_CYCLE(80 + 52 * ui, cycle_time) << 8 |
-                  NS_TO_CYCLE(0x40, cycle_time);
+       timcon3 = NS_TO_CYCLE(0x40, cycle_time) | (2 * T_LPX) << 16 |
+                 NS_TO_CYCLE(80 + 52 * ui, cycle_time) << 8;
 
        writel(timcon0, dsi->regs + DSI_PHY_TIMECON0);
        writel(timcon1, dsi->regs + DSI_PHY_TIMECON1);
@@ -202,19 +206,47 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
 {
        struct device *dev = dsi->dev;
        int ret;
+       u64 pixel_clock, total_bits;
+       u32 htotal, htotal_bits, bit_per_pixel, overhead_cycles, overhead_bits;
 
        if (++dsi->refcount != 1)
                return 0;
 
+       switch (dsi->format) {
+       case MIPI_DSI_FMT_RGB565:
+               bit_per_pixel = 16;
+               break;
+       case MIPI_DSI_FMT_RGB666_PACKED:
+               bit_per_pixel = 18;
+               break;
+       case MIPI_DSI_FMT_RGB666:
+       case MIPI_DSI_FMT_RGB888:
+       default:
+               bit_per_pixel = 24;
+               break;
+       }
+
        /**
-        * data_rate = (pixel_clock / 1000) * pixel_dipth * mipi_ratio;
-        * pixel_clock unit is Khz, data_rata unit is MHz, so need divide 1000.
-        * mipi_ratio is mipi clk coefficient for balance the pixel clk in mipi.
-        * we set mipi_ratio is 1.05.
+        * vm.pixelclock is in kHz, pixel_clock unit is Hz, so multiply by 1000
+        * htotal_time = htotal * byte_per_pixel / num_lanes
+        * overhead_time = lpx + hs_prepare + hs_zero + hs_trail + hs_exit
+        * mipi_ratio = (htotal_time + overhead_time) / htotal_time
+        * data_rate = pixel_clock * bit_per_pixel * mipi_ratio / num_lanes;
         */
-       dsi->data_rate = dsi->vm.pixelclock * 3 * 21 / (1 * 1000 * 10);
+       pixel_clock = dsi->vm.pixelclock * 1000;
+       htotal = dsi->vm.hactive + dsi->vm.hback_porch + dsi->vm.hfront_porch +
+                       dsi->vm.hsync_len;
+       htotal_bits = htotal * bit_per_pixel;
+
+       overhead_cycles = T_LPX + T_HS_PREP + T_HS_ZERO + T_HS_TRAIL +
+                       T_HS_EXIT;
+       overhead_bits = overhead_cycles * dsi->lanes * 8;
+       total_bits = htotal_bits + overhead_bits;
+
+       dsi->data_rate = DIV_ROUND_UP_ULL(pixel_clock * total_bits,
+                                         htotal * dsi->lanes);
 
-       ret = clk_set_rate(dsi->hs_clk, dsi->data_rate * 1000000);
+       ret = clk_set_rate(dsi->hs_clk, dsi->data_rate);
        if (ret < 0) {
                dev_err(dev, "Failed to set data rate: %d\n", ret);
                goto err_refcount;
index 71227deef21b1ea96d6a2594b98a584d41ad6320..0e8c4d9af34069f55e8784d8e43b6e4e56251cfa 100644 (file)
@@ -1133,12 +1133,6 @@ static int mtk_hdmi_output_set_display_mode(struct mtk_hdmi *hdmi,
        phy_power_on(hdmi->phy);
        mtk_hdmi_aud_output_config(hdmi, mode);
 
-       mtk_hdmi_setup_audio_infoframe(hdmi);
-       mtk_hdmi_setup_avi_infoframe(hdmi, mode);
-       mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
-       if (mode->flags & DRM_MODE_FLAG_3D_MASK)
-               mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
-
        mtk_hdmi_hw_vid_black(hdmi, false);
        mtk_hdmi_hw_aud_unmute(hdmi);
        mtk_hdmi_hw_send_av_unmute(hdmi);
@@ -1401,6 +1395,16 @@ static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
        hdmi->powered = true;
 }
 
+static void mtk_hdmi_send_infoframe(struct mtk_hdmi *hdmi,
+                                   struct drm_display_mode *mode)
+{
+       mtk_hdmi_setup_audio_infoframe(hdmi);
+       mtk_hdmi_setup_avi_infoframe(hdmi, mode);
+       mtk_hdmi_setup_spd_infoframe(hdmi, "mediatek", "On-chip HDMI");
+       if (mode->flags & DRM_MODE_FLAG_3D_MASK)
+               mtk_hdmi_setup_vendor_specific_infoframe(hdmi, mode);
+}
+
 static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge)
 {
        struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
@@ -1409,6 +1413,7 @@ static void mtk_hdmi_bridge_enable(struct drm_bridge *bridge)
        clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PLL]);
        clk_prepare_enable(hdmi->clk[MTK_HDMI_CLK_HDMI_PIXEL]);
        phy_power_on(hdmi->phy);
+       mtk_hdmi_send_infoframe(hdmi, &hdmi->mode);
 
        hdmi->enabled = true;
 }
index 8a24754b440f06585ec67bda44a182cc34e00c84..51cb9cfb6646e3f46a63a2073b923ef6b3f02b2d 100644 (file)
@@ -265,6 +265,9 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
        unsigned int pre_div;
        unsigned int div;
+       unsigned int pre_ibias;
+       unsigned int hdmi_ibias;
+       unsigned int imp_en;
 
        dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__,
                rate, parent_rate);
@@ -298,18 +301,31 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                          (0x1 << PLL_BR_SHIFT),
                          RG_HDMITX_PLL_BP | RG_HDMITX_PLL_BC |
                          RG_HDMITX_PLL_BR);
-       mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_PRD_IMP_EN);
+       if (rate < 165000000) {
+               mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3,
+                                       RG_HDMITX_PRD_IMP_EN);
+               pre_ibias = 0x3;
+               imp_en = 0x0;
+               hdmi_ibias = hdmi_phy->ibias;
+       } else {
+               mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON3,
+                                     RG_HDMITX_PRD_IMP_EN);
+               pre_ibias = 0x6;
+               imp_en = 0xf;
+               hdmi_ibias = hdmi_phy->ibias_up;
+       }
        mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON4,
-                         (0x3 << PRD_IBIAS_CLK_SHIFT) |
-                         (0x3 << PRD_IBIAS_D2_SHIFT) |
-                         (0x3 << PRD_IBIAS_D1_SHIFT) |
-                         (0x3 << PRD_IBIAS_D0_SHIFT),
+                         (pre_ibias << PRD_IBIAS_CLK_SHIFT) |
+                         (pre_ibias << PRD_IBIAS_D2_SHIFT) |
+                         (pre_ibias << PRD_IBIAS_D1_SHIFT) |
+                         (pre_ibias << PRD_IBIAS_D0_SHIFT),
                          RG_HDMITX_PRD_IBIAS_CLK |
                          RG_HDMITX_PRD_IBIAS_D2 |
                          RG_HDMITX_PRD_IBIAS_D1 |
                          RG_HDMITX_PRD_IBIAS_D0);
        mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON3,
-                         (0x0 << DRV_IMP_EN_SHIFT), RG_HDMITX_DRV_IMP_EN);
+                         (imp_en << DRV_IMP_EN_SHIFT),
+                         RG_HDMITX_DRV_IMP_EN);
        mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON6,
                          (hdmi_phy->drv_imp_clk << DRV_IMP_CLK_SHIFT) |
                          (hdmi_phy->drv_imp_d2 << DRV_IMP_D2_SHIFT) |
@@ -318,12 +334,14 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                          RG_HDMITX_DRV_IMP_CLK | RG_HDMITX_DRV_IMP_D2 |
                          RG_HDMITX_DRV_IMP_D1 | RG_HDMITX_DRV_IMP_D0);
        mtk_hdmi_phy_mask(hdmi_phy, HDMI_CON5,
-                         (hdmi_phy->ibias << DRV_IBIAS_CLK_SHIFT) |
-                         (hdmi_phy->ibias << DRV_IBIAS_D2_SHIFT) |
-                         (hdmi_phy->ibias << DRV_IBIAS_D1_SHIFT) |
-                         (hdmi_phy->ibias << DRV_IBIAS_D0_SHIFT),
-                         RG_HDMITX_DRV_IBIAS_CLK | RG_HDMITX_DRV_IBIAS_D2 |
-                         RG_HDMITX_DRV_IBIAS_D1 | RG_HDMITX_DRV_IBIAS_D0);
+                         (hdmi_ibias << DRV_IBIAS_CLK_SHIFT) |
+                         (hdmi_ibias << DRV_IBIAS_D2_SHIFT) |
+                         (hdmi_ibias << DRV_IBIAS_D1_SHIFT) |
+                         (hdmi_ibias << DRV_IBIAS_D0_SHIFT),
+                         RG_HDMITX_DRV_IBIAS_CLK |
+                         RG_HDMITX_DRV_IBIAS_D2 |
+                         RG_HDMITX_DRV_IBIAS_D1 |
+                         RG_HDMITX_DRV_IBIAS_D0);
        return 0;
 }
 
index 919b35f2ad2487443c97dc3af28916d67ba6c0fb..dcf7d11ac380d0e6b25e1b7e64440913572d7609 100644 (file)
@@ -266,6 +266,9 @@ int mgag200_mm_init(struct mga_device *mdev)
                return ret;
        }
 
+       arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
+                                  pci_resource_len(dev->pdev, 0));
+
        mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
                                         pci_resource_len(dev->pdev, 0));
 
@@ -274,10 +277,14 @@ int mgag200_mm_init(struct mga_device *mdev)
 
 void mgag200_mm_fini(struct mga_device *mdev)
 {
+       struct drm_device *dev = mdev->dev;
+
        ttm_bo_device_release(&mdev->ttm.bdev);
 
        mgag200_ttm_global_release(mdev);
 
+       arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
+                               pci_resource_len(dev->pdev, 0));
        arch_phys_wc_del(mdev->fb_mtrr);
        mdev->fb_mtrr = 0;
 }
index f05ed0e1f3d655d0009438fd923e9438c79be1d5..6f240021705b0c493457560f1782fdd9483c5b98 100644 (file)
@@ -139,6 +139,7 @@ struct msm_dsi_host {
 
        u32 err_work_state;
        struct work_struct err_work;
+       struct work_struct hpd_work;
        struct workqueue_struct *workqueue;
 
        /* DSI 6G TX buffer*/
@@ -1294,6 +1295,14 @@ static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host)
        wmb();  /* make sure dsi controller enabled again */
 }
 
+static void dsi_hpd_worker(struct work_struct *work)
+{
+       struct msm_dsi_host *msm_host =
+               container_of(work, struct msm_dsi_host, hpd_work);
+
+       drm_helper_hpd_irq_event(msm_host->dev);
+}
+
 static void dsi_err_worker(struct work_struct *work)
 {
        struct msm_dsi_host *msm_host =
@@ -1480,7 +1489,7 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
 
        DBG("id=%d", msm_host->id);
        if (msm_host->dev)
-               drm_helper_hpd_irq_event(msm_host->dev);
+               queue_work(msm_host->workqueue, &msm_host->hpd_work);
 
        return 0;
 }
@@ -1494,7 +1503,7 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
 
        DBG("id=%d", msm_host->id);
        if (msm_host->dev)
-               drm_helper_hpd_irq_event(msm_host->dev);
+               queue_work(msm_host->workqueue, &msm_host->hpd_work);
 
        return 0;
 }
@@ -1748,6 +1757,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
        /* setup workqueue */
        msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
        INIT_WORK(&msm_host->err_work, dsi_err_worker);
+       INIT_WORK(&msm_host->hpd_work, dsi_hpd_worker);
 
        msm_dsi->host = &msm_host->base;
        msm_dsi->id = msm_host->id;
index 598fdaff0a41a051fa165d79e386aab7a7f9bd84..26e3a01a99c2b71dde9fed5bd548ee17b61e2df4 100644 (file)
@@ -521,6 +521,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
                .parent_names = (const char *[]){ "xo" },
                .num_parents = 1,
                .name = vco_name,
+               .flags = CLK_IGNORE_UNUSED,
                .ops = &clk_ops_dsi_pll_28nm_vco,
        };
        struct device *dev = &pll_28nm->pdev->dev;
index 38c90e1eb00286b4ce0bb9dd49e30115f60869bc..49008451085b86ccb84ee3760c406554db51fd49 100644 (file)
@@ -412,6 +412,7 @@ static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
        struct clk_init_data vco_init = {
                .parent_names = (const char *[]){ "pxo" },
                .num_parents = 1,
+               .flags = CLK_IGNORE_UNUSED,
                .ops = &clk_ops_dsi_pll_28nm_vco,
        };
        struct device *dev = &pll_28nm->pdev->dev;
index aa94a553794f50eed7d5c49dd01d594c96113baa..143eab46ba687b0b1a89969598736bc75e750809 100644 (file)
@@ -702,6 +702,7 @@ static struct clk_init_data pll_init = {
        .ops = &hdmi_8996_pll_ops,
        .parent_names = hdmi_pll_parents,
        .num_parents = ARRAY_SIZE(hdmi_pll_parents),
+       .flags = CLK_IGNORE_UNUSED,
 };
 
 int msm_hdmi_pll_8996_init(struct platform_device *pdev)
index 92da69aa6187e64fa6cbb515a4698bf32f57db54..99590758c68b7cf8e296928db1bab5ce5b2df4c4 100644 (file)
@@ -424,6 +424,7 @@ static struct clk_init_data pll_init = {
        .ops = &hdmi_pll_ops,
        .parent_names = hdmi_pll_parents,
        .num_parents = ARRAY_SIZE(hdmi_pll_parents),
+       .flags = CLK_IGNORE_UNUSED,
 };
 
 int msm_hdmi_pll_8960_init(struct platform_device *pdev)
index ac9e4cde13804f78333d5d6e101b37511949a5e8..8b4e3004f4518d19341b24c140606404853e379b 100644 (file)
@@ -272,7 +272,7 @@ const struct mdp5_cfg_hw msm8x16_config = {
                .count = 2,
                .base = { 0x14000, 0x16000 },
                .caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
-                               MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
+                               MDP_PIPE_CAP_DECIMATION,
        },
        .pipe_dma = {
                .count = 1,
@@ -282,7 +282,7 @@ const struct mdp5_cfg_hw msm8x16_config = {
        .lm = {
                .count = 2, /* LM0 and LM3 */
                .base = { 0x44000, 0x47000 },
-               .nb_stages = 5,
+               .nb_stages = 8,
                .max_width = 2048,
                .max_height = 0xFFFF,
        },
index fa2be7ce9468768eb6737a12ec29d11fc52f49f0..c205c360e16dcbdf83120e102e0a6854b852959f 100644 (file)
@@ -223,12 +223,7 @@ static void blend_setup(struct drm_crtc *crtc)
                plane_cnt++;
        }
 
-       /*
-       * If there is no base layer, enable border color.
-       * Although it's not possbile in current blend logic,
-       * put it here as a reminder.
-       */
-       if (!pstates[STAGE_BASE] && plane_cnt) {
+       if (!pstates[STAGE_BASE]) {
                ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
                DBG("Border Color is enabled");
        }
@@ -365,6 +360,15 @@ static int pstate_cmp(const void *a, const void *b)
        return pa->state->zpos - pb->state->zpos;
 }
 
+/* is there a helper for this? */
+static bool is_fullscreen(struct drm_crtc_state *cstate,
+               struct drm_plane_state *pstate)
+{
+       return (pstate->crtc_x <= 0) && (pstate->crtc_y <= 0) &&
+               ((pstate->crtc_x + pstate->crtc_w) >= cstate->mode.hdisplay) &&
+               ((pstate->crtc_y + pstate->crtc_h) >= cstate->mode.vdisplay);
+}
+
 static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
                struct drm_crtc_state *state)
 {
@@ -375,21 +379,11 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
        struct plane_state pstates[STAGE_MAX + 1];
        const struct mdp5_cfg_hw *hw_cfg;
        const struct drm_plane_state *pstate;
-       int cnt = 0, i;
+       int cnt = 0, base = 0, i;
 
        DBG("%s: check", mdp5_crtc->name);
 
-       /* verify that there are not too many planes attached to crtc
-        * and that we don't have conflicting mixer stages:
-        */
-       hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
        drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
-               if (cnt >= (hw_cfg->lm.nb_stages)) {
-                       dev_err(dev->dev, "too many planes!\n");
-                       return -EINVAL;
-               }
-
-
                pstates[cnt].plane = plane;
                pstates[cnt].state = to_mdp5_plane_state(pstate);
 
@@ -399,8 +393,24 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
        /* assign a stage based on sorted zpos property */
        sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
 
+       /* if the bottom-most layer is not fullscreen, we need to use
+        * it for solid-color:
+        */
+       if ((cnt > 0) && !is_fullscreen(state, &pstates[0].state->base))
+               base++;
+
+       /* verify that there are not too many planes attached to crtc
+        * and that we don't have conflicting mixer stages:
+        */
+       hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+       if ((cnt + base) >= hw_cfg->lm.nb_stages) {
+               dev_err(dev->dev, "too many planes!\n");
+               return -EINVAL;
+       }
+
        for (i = 0; i < cnt; i++) {
-               pstates[i].state->stage = STAGE_BASE + i;
+               pstates[i].state->stage = STAGE_BASE + i + base;
                DBG("%s: assign pipe %s on stage=%d", mdp5_crtc->name,
                                pipe2name(mdp5_plane_pipe(pstates[i].plane)),
                                pstates[i].state->stage);
index 951c002b05df2701977eb3f8570aa004f1cddd28..83bf997dda03cd9df09bd356ae661156351aaee2 100644 (file)
@@ -292,8 +292,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
                format = to_mdp_format(msm_framebuffer_format(state->fb));
                if (MDP_FORMAT_IS_YUV(format) &&
                        !pipe_supports_yuv(mdp5_plane->caps)) {
-                       dev_err(plane->dev->dev,
-                               "Pipe doesn't support YUV\n");
+                       DBG("Pipe doesn't support YUV\n");
 
                        return -EINVAL;
                }
@@ -301,8 +300,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
                if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) &&
                        (((state->src_w >> 16) != state->crtc_w) ||
                        ((state->src_h >> 16) != state->crtc_h))) {
-                       dev_err(plane->dev->dev,
-                               "Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
+                       DBG("Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
                                state->src_w >> 16, state->src_h >> 16,
                                state->crtc_w, state->crtc_h);
 
@@ -313,8 +311,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
                vflip = !!(state->rotation & DRM_REFLECT_Y);
                if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
                        (hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
-                       dev_err(plane->dev->dev,
-                               "Pipe doesn't support flip\n");
+                       DBG("Pipe doesn't support flip\n");
 
                        return -EINVAL;
                }
index fb5c0b0a7594adcb0f38858cce0fc87d786f4eaa..46568fc80848f1376122d4936e662310e6cdb4b4 100644 (file)
@@ -228,7 +228,7 @@ static int msm_drm_uninit(struct device *dev)
        flush_workqueue(priv->atomic_wq);
        destroy_workqueue(priv->atomic_wq);
 
-       if (kms)
+       if (kms && kms->funcs)
                kms->funcs->destroy(kms);
 
        if (gpu) {
index 283d2841ba58137efa28ea4c2cef3872b4cb5202..192b2d3a79cb221e4b067b5b153d3a913edd6ffc 100644 (file)
@@ -163,6 +163,9 @@ void msm_gem_shrinker_init(struct drm_device *dev)
 void msm_gem_shrinker_cleanup(struct drm_device *dev)
 {
        struct msm_drm_private *priv = dev->dev_private;
-       WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier));
-       unregister_shrinker(&priv->shrinker);
+
+       if (priv->shrinker.nr_deferred) {
+               WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier));
+               unregister_shrinker(&priv->shrinker);
+       }
 }
index dc57b628e07473ad6e0810085c5fd960ef6b49bc..193573d191e520a12ccdde4a791ebdf8e64a334c 100644 (file)
@@ -240,7 +240,8 @@ static bool nouveau_pr3_present(struct pci_dev *pdev)
        if (!parent_adev)
                return false;
 
-       return acpi_has_method(parent_adev->handle, "_PR3");
+       return parent_adev->power.flags.power_resources &&
+               acpi_has_method(parent_adev->handle, "_PR3");
 }
 
 static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
index 1825dbc331926c84de69e13606f38cf4c80a2bed..a6dbe8258040d24b67a7e774f4785e1b1efeb32f 100644 (file)
@@ -398,6 +398,9 @@ nouveau_ttm_init(struct nouveau_drm *drm)
        /* VRAM init */
        drm->gem.vram_available = drm->device.info.ram_user;
 
+       arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1),
+                                  device->func->resource_size(device, 1));
+
        ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
                              drm->gem.vram_available >> PAGE_SHIFT);
        if (ret) {
@@ -430,6 +433,8 @@ nouveau_ttm_init(struct nouveau_drm *drm)
 void
 nouveau_ttm_fini(struct nouveau_drm *drm)
 {
+       struct nvkm_device *device = nvxx_device(&drm->device);
+
        ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM);
        ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT);
 
@@ -439,4 +444,7 @@ nouveau_ttm_fini(struct nouveau_drm *drm)
 
        arch_phys_wc_del(drm->ttm.mtrr);
        drm->ttm.mtrr = 0;
+       arch_io_free_memtype_wc(device->func->resource_addr(device, 1),
+                               device->func->resource_size(device, 1));
+
 }
index 103fc8650197bfe8efd6903ba29ba1c3906ccd2a..a0d4a0522fdc98582e99b1016d482de148e62f16 100644 (file)
@@ -1396,9 +1396,7 @@ static void cayman_pcie_gart_fini(struct radeon_device *rdev)
 void cayman_cp_int_cntl_setup(struct radeon_device *rdev,
                              int ring, u32 cp_int_cntl)
 {
-       u32 srbm_gfx_cntl = RREG32(SRBM_GFX_CNTL) & ~3;
-
-       WREG32(SRBM_GFX_CNTL, srbm_gfx_cntl | (ring & 3));
+       WREG32(SRBM_GFX_CNTL, RINGID(ring));
        WREG32(CP_INT_CNTL, cp_int_cntl);
 }
 
index 6a4b020dd0b45aa504bcb7acd68c49a0ddfc9328..5a26eb4545aae4afea2dc83d6b5e615b1ddcfff3 100644 (file)
@@ -156,19 +156,20 @@ u32 r600_dpm_get_vblank_time(struct radeon_device *rdev)
        struct drm_device *dev = rdev->ddev;
        struct drm_crtc *crtc;
        struct radeon_crtc *radeon_crtc;
-       u32 line_time_us, vblank_lines;
+       u32 vblank_in_pixels;
        u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
 
        if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        radeon_crtc = to_radeon_crtc(crtc);
                        if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
-                               line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) /
-                                       radeon_crtc->hw_mode.clock;
-                               vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end -
-                                       radeon_crtc->hw_mode.crtc_vdisplay +
-                                       (radeon_crtc->v_border * 2);
-                               vblank_time_us = vblank_lines * line_time_us;
+                               vblank_in_pixels =
+                                       radeon_crtc->hw_mode.crtc_htotal *
+                                       (radeon_crtc->hw_mode.crtc_vblank_end -
+                                        radeon_crtc->hw_mode.crtc_vdisplay +
+                                        (radeon_crtc->v_border * 2));
+
+                               vblank_time_us = vblank_in_pixels * 1000 / radeon_crtc->hw_mode.clock;
                                break;
                        }
                }
index 2fdcd04bc93f7b9c6abf5d84752836e154d566b0..0ae13cd2addaa2f4e53a9b69903c3095912d8460 100644 (file)
@@ -34,6 +34,7 @@ struct radeon_atpx {
 
 static struct radeon_atpx_priv {
        bool atpx_detected;
+       bool bridge_pm_usable;
        /* handle for device - and atpx */
        acpi_handle dhandle;
        struct radeon_atpx atpx;
@@ -203,7 +204,11 @@ static int radeon_atpx_validate(struct radeon_atpx *atpx)
        atpx->is_hybrid = false;
        if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) {
                printk("ATPX Hybrid Graphics\n");
-               atpx->functions.power_cntl = false;
+               /*
+                * Disable legacy PM methods only when pcie port PM is usable,
+                * otherwise the device might fail to power off or power on.
+                */
+               atpx->functions.power_cntl = !radeon_atpx_priv.bridge_pm_usable;
                atpx->is_hybrid = true;
        }
 
@@ -548,11 +553,16 @@ static bool radeon_atpx_detect(void)
        struct pci_dev *pdev = NULL;
        bool has_atpx = false;
        int vga_count = 0;
+       bool d3_supported = false;
+       struct pci_dev *parent_pdev;
 
        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
                vga_count++;
 
                has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
+
+               parent_pdev = pci_upstream_bridge(pdev);
+               d3_supported |= parent_pdev && parent_pdev->bridge_d3;
        }
 
        /* some newer PX laptops mark the dGPU as a non-VGA display device */
@@ -560,6 +570,9 @@ static bool radeon_atpx_detect(void)
                vga_count++;
 
                has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
+
+               parent_pdev = pci_upstream_bridge(pdev);
+               d3_supported |= parent_pdev && parent_pdev->bridge_d3;
        }
 
        if (has_atpx && vga_count == 2) {
@@ -567,6 +580,7 @@ static bool radeon_atpx_detect(void)
                printk(KERN_INFO "vga_switcheroo: detected switching method %s handle\n",
                       acpi_method_name);
                radeon_atpx_priv.atpx_detected = true;
+               radeon_atpx_priv.bridge_pm_usable = d3_supported;
                radeon_atpx_init();
                return true;
        }
index 50e96d2c593dafe05c0e0205288c7f2b7c6a71d9..27affbde058c626eec6ae5b5b77cd9a2d4601ba9 100644 (file)
@@ -927,6 +927,16 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
        return ret;
 }
 
+static void radeon_connector_unregister(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+       if (radeon_connector->ddc_bus && radeon_connector->ddc_bus->has_aux) {
+               drm_dp_aux_unregister(&radeon_connector->ddc_bus->aux);
+               radeon_connector->ddc_bus->has_aux = false;
+       }
+}
+
 static void radeon_connector_destroy(struct drm_connector *connector)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -984,6 +994,7 @@ static const struct drm_connector_funcs radeon_lvds_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_lvds_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .early_unregister = radeon_connector_unregister,
        .destroy = radeon_connector_destroy,
        .set_property = radeon_lvds_set_property,
 };
@@ -1111,6 +1122,7 @@ static const struct drm_connector_funcs radeon_vga_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_vga_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .early_unregister = radeon_connector_unregister,
        .destroy = radeon_connector_destroy,
        .set_property = radeon_connector_set_property,
 };
@@ -1188,6 +1200,7 @@ static const struct drm_connector_funcs radeon_tv_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
        .detect = radeon_tv_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
+       .early_unregister = radeon_connector_unregister,
        .destroy = radeon_connector_destroy,
        .set_property = radeon_connector_set_property,
 };
@@ -1519,6 +1532,7 @@ static const struct drm_connector_funcs radeon_dvi_connector_funcs = {
        .detect = radeon_dvi_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = radeon_connector_set_property,
+       .early_unregister = radeon_connector_unregister,
        .destroy = radeon_connector_destroy,
        .force = radeon_dvi_force,
 };
@@ -1832,6 +1846,7 @@ static const struct drm_connector_funcs radeon_dp_connector_funcs = {
        .detect = radeon_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = radeon_connector_set_property,
+       .early_unregister = radeon_connector_unregister,
        .destroy = radeon_connector_destroy,
        .force = radeon_dvi_force,
 };
@@ -1841,6 +1856,7 @@ static const struct drm_connector_funcs radeon_edp_connector_funcs = {
        .detect = radeon_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = radeon_lvds_set_property,
+       .early_unregister = radeon_connector_unregister,
        .destroy = radeon_connector_destroy,
        .force = radeon_dvi_force,
 };
@@ -1850,6 +1866,7 @@ static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
        .detect = radeon_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = radeon_lvds_set_property,
+       .early_unregister = radeon_connector_unregister,
        .destroy = radeon_connector_destroy,
        .force = radeon_dvi_force,
 };
index eb92aef46e3cfcf99a07d26272fac7725d0cfaa8..621af069a3d2a5f1175bac236d4421db594eca07 100644 (file)
@@ -104,6 +104,14 @@ static const char radeon_family_name[][16] = {
        "LAST",
 };
 
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_has_atpx_dgpu_power_cntl(void);
+bool radeon_is_atpx_hybrid(void);
+#else
+static inline bool radeon_has_atpx_dgpu_power_cntl(void) { return false; }
+static inline bool radeon_is_atpx_hybrid(void) { return false; }
+#endif
+
 #define RADEON_PX_QUIRK_DISABLE_PX  (1 << 0)
 #define RADEON_PX_QUIRK_LONG_WAKEUP (1 << 1)
 
@@ -160,6 +168,11 @@ static void radeon_device_handle_px_quirks(struct radeon_device *rdev)
 
        if (rdev->px_quirk_flags & RADEON_PX_QUIRK_DISABLE_PX)
                rdev->flags &= ~RADEON_IS_PX;
+
+       /* disable PX is the system doesn't support dGPU power control or hybrid gfx */
+       if (!radeon_is_atpx_hybrid() &&
+           !radeon_has_atpx_dgpu_power_cntl())
+               rdev->flags &= ~RADEON_IS_PX;
 }
 
 /**
index b8ab30a7dd6d2f2d215415751539c652a3b1ed55..cdb8cb568c15310589039b2f0c56faf5cbf11b9c 100644 (file)
@@ -1675,20 +1675,20 @@ int radeon_modeset_init(struct radeon_device *rdev)
 
 void radeon_modeset_fini(struct radeon_device *rdev)
 {
-       radeon_fbdev_fini(rdev);
-       kfree(rdev->mode_info.bios_hardcoded_edid);
-
-       /* free i2c buses */
-       radeon_i2c_fini(rdev);
-
        if (rdev->mode_info.mode_config_initialized) {
-               radeon_afmt_fini(rdev);
                drm_kms_helper_poll_fini(rdev->ddev);
                radeon_hpd_fini(rdev);
                drm_crtc_force_disable_all(rdev->ddev);
+               radeon_fbdev_fini(rdev);
+               radeon_afmt_fini(rdev);
                drm_mode_config_cleanup(rdev->ddev);
                rdev->mode_info.mode_config_initialized = false;
        }
+
+       kfree(rdev->mode_info.bios_hardcoded_edid);
+
+       /* free i2c buses */
+       radeon_i2c_fini(rdev);
 }
 
 static bool is_hdtv_mode(const struct drm_display_mode *mode)
index 2d465648856a03156c878993ab2cc24755aec74f..474a8a1886f712114caf20b8484929f5009a3313 100644 (file)
@@ -105,7 +105,7 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg
 
        tmp &= AUX_HPD_SEL(0x7);
        tmp |= AUX_HPD_SEL(chan->rec.hpd);
-       tmp |= AUX_EN | AUX_LS_READ_EN | AUX_HPD_DISCON(0x1);
+       tmp |= AUX_EN | AUX_LS_READ_EN;
 
        WREG32(AUX_CONTROL + aux_offset[instance], tmp);
 
index 91c8f433956605e1f5106b69df1af9123e3bd2c5..00ea0002b539b9e9b5b0a063f62deb3b7638fd56 100644 (file)
  *   2.45.0 - Allow setting shader registers using DMA/COPY packet3 on SI
  *   2.46.0 - Add PFP_SYNC_ME support on evergreen
  *   2.47.0 - Add UVD_NO_OP register support
+ *   2.48.0 - TA_CS_BC_BASE_ADDR allowed on SI
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       47
+#define KMS_DRIVER_MINOR       48
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
index 021aa005623f804be130179398a617291032c92b..29f7817af821babcfe36e148c6f5a0fb8065e035 100644 (file)
@@ -982,9 +982,8 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
 {
        if (!i2c)
                return;
+       WARN_ON(i2c->has_aux);
        i2c_del_adapter(&i2c->adapter);
-       if (i2c->has_aux)
-               drm_dp_aux_unregister(&i2c->aux);
        kfree(i2c);
 }
 
index be30861afae9a8e2bb1fcc6ee261b5285f4dcb44..41b72ce6613febc033c0e37fe68655faeca65554 100644 (file)
@@ -446,6 +446,10 @@ void radeon_bo_force_delete(struct radeon_device *rdev)
 
 int radeon_bo_init(struct radeon_device *rdev)
 {
+       /* reserve PAT memory space to WC for VRAM */
+       arch_io_reserve_memtype_wc(rdev->mc.aper_base,
+                                  rdev->mc.aper_size);
+
        /* Add an MTRR for the VRAM */
        if (!rdev->fastfb_working) {
                rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base,
@@ -463,6 +467,7 @@ void radeon_bo_fini(struct radeon_device *rdev)
 {
        radeon_ttm_fini(rdev);
        arch_phys_wc_del(rdev->mc.vram_mtrr);
+       arch_io_free_memtype_wc(rdev->mc.aper_base, rdev->mc.aper_size);
 }
 
 /* Returns how many bytes TTM can move per IB.
index 455268214b893eac36e8bbd65d5e2b18d2735483..3de5e6e216628233ef1ba997bfcab6ae09d24621 100644 (file)
@@ -566,7 +566,8 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
                uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
                struct page **pages = ttm->pages + pinned;
 
-               r = get_user_pages(userptr, num_pages, write, 0, pages, NULL);
+               r = get_user_pages(userptr, num_pages, write ? FOLL_WRITE : 0,
+                                  pages, NULL);
                if (r < 0)
                        goto release_pages;
 
index 7ee9aafbdf744bc0a97f358767e5b2178f24c41a..e402be8821c45271a276f721f1eb9c94fcf4afb5 100644 (file)
@@ -4431,6 +4431,7 @@ static bool si_vm_reg_valid(u32 reg)
        case SPI_CONFIG_CNTL:
        case SPI_CONFIG_CNTL_1:
        case TA_CNTL_AUX:
+       case TA_CS_BC_BASE_ADDR:
                return true;
        default:
                DRM_ERROR("Invalid register 0x%x in CS\n", reg);
index 89bdf20344aeffdcbbcef609e131b8a37f6423cf..c49934527a87852bf207b26e04c4de5939df8c53 100644 (file)
@@ -2999,6 +2999,49 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
        int i;
        struct si_dpm_quirk *p = si_dpm_quirk_list;
 
+       /* limit all SI kickers */
+       if (rdev->family == CHIP_PITCAIRN) {
+               if ((rdev->pdev->revision == 0x81) ||
+                   (rdev->pdev->device == 0x6810) ||
+                   (rdev->pdev->device == 0x6811) ||
+                   (rdev->pdev->device == 0x6816) ||
+                   (rdev->pdev->device == 0x6817) ||
+                   (rdev->pdev->device == 0x6806))
+                       max_mclk = 120000;
+       } else if (rdev->family == CHIP_VERDE) {
+               if ((rdev->pdev->revision == 0x81) ||
+                   (rdev->pdev->revision == 0x83) ||
+                   (rdev->pdev->revision == 0x87) ||
+                   (rdev->pdev->device == 0x6820) ||
+                   (rdev->pdev->device == 0x6821) ||
+                   (rdev->pdev->device == 0x6822) ||
+                   (rdev->pdev->device == 0x6823) ||
+                   (rdev->pdev->device == 0x682A) ||
+                   (rdev->pdev->device == 0x682B)) {
+                       max_sclk = 75000;
+                       max_mclk = 80000;
+               }
+       } else if (rdev->family == CHIP_OLAND) {
+               if ((rdev->pdev->revision == 0xC7) ||
+                   (rdev->pdev->revision == 0x80) ||
+                   (rdev->pdev->revision == 0x81) ||
+                   (rdev->pdev->revision == 0x83) ||
+                   (rdev->pdev->device == 0x6604) ||
+                   (rdev->pdev->device == 0x6605)) {
+                       max_sclk = 75000;
+                       max_mclk = 80000;
+               }
+       } else if (rdev->family == CHIP_HAINAN) {
+               if ((rdev->pdev->revision == 0x81) ||
+                   (rdev->pdev->revision == 0x83) ||
+                   (rdev->pdev->revision == 0xC3) ||
+                   (rdev->pdev->device == 0x6664) ||
+                   (rdev->pdev->device == 0x6665) ||
+                   (rdev->pdev->device == 0x6667)) {
+                       max_sclk = 75000;
+                       max_mclk = 80000;
+               }
+       }
        /* Apply dpm quirks */
        while (p && p->chip_device != 0) {
                if (rdev->pdev->vendor == p->chip_vendor &&
@@ -3011,16 +3054,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                }
                ++p;
        }
-       /* limit mclk on all R7 370 parts for stability */
-       if (rdev->pdev->device == 0x6811 &&
-           rdev->pdev->revision == 0x81)
-               max_mclk = 120000;
-       /* limit sclk/mclk on Jet parts for stability */
-       if (rdev->pdev->device == 0x6665 &&
-           rdev->pdev->revision == 0xc3) {
-               max_sclk = 75000;
-               max_mclk = 80000;
-       }
 
        if (rps->vce_active) {
                rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
index eb220eecba789aaf40ced21852a8d98441e55a3b..65a911ddd509d29d2a5d460ada79674e947a96f3 100644 (file)
 #define        SPI_LB_CU_MASK                                  0x9354
 
 #define        TA_CNTL_AUX                                     0x9508
+#define        TA_CS_BC_BASE_ADDR                              0x950C
 
 #define CC_RB_BACKEND_DISABLE                          0x98F4
 #define                BACKEND_DISABLE(x)                      ((x) << 16)
index bd9c3bb9252c68520af8233412c69253bfd04838..392c7e6de04272dc3336f0c197c283f3319ad993 100644 (file)
@@ -231,8 +231,16 @@ static int rcar_du_atomic_check(struct drm_device *dev,
        struct rcar_du_device *rcdu = dev->dev_private;
        int ret;
 
-       ret = drm_atomic_helper_check(dev, state);
-       if (ret < 0)
+       ret = drm_atomic_helper_check_modeset(dev, state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_normalize_zpos(dev, state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_helper_check_planes(dev, state);
+       if (ret)
                return ret;
 
        if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
index 2784919a73664c6287e7d5812839347d572011ca..9df308565f6cac7b68ff8b81cd97a3ef3a005834 100644 (file)
@@ -195,6 +195,26 @@ static void sti_atomic_work(struct work_struct *work)
        sti_atomic_complete(private, private->commit.state);
 }
 
+static int sti_atomic_check(struct drm_device *dev,
+                           struct drm_atomic_state *state)
+{
+       int ret;
+
+       ret = drm_atomic_helper_check_modeset(dev, state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_normalize_zpos(dev, state);
+       if (ret)
+               return ret;
+
+       ret = drm_atomic_helper_check_planes(dev, state);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
 static int sti_atomic_commit(struct drm_device *drm,
                             struct drm_atomic_state *state, bool nonblock)
 {
@@ -248,7 +268,7 @@ static void sti_output_poll_changed(struct drm_device *ddev)
 static const struct drm_mode_config_funcs sti_mode_config_funcs = {
        .fb_create = drm_fb_cma_create,
        .output_poll_changed = sti_output_poll_changed,
-       .atomic_check = drm_atomic_helper_check,
+       .atomic_check = sti_atomic_check,
        .atomic_commit = sti_atomic_commit,
 };
 
index 0da9862ad8ed928e23a6a1e089551967ad5273e8..70e9fd59c5a24650f7e89f2db5d1a780cc2683d9 100644 (file)
@@ -142,9 +142,9 @@ static int sun4i_drv_bind(struct device *dev)
 
        /* Create our layers */
        drv->layers = sun4i_layers_init(drm);
-       if (!drv->layers) {
+       if (IS_ERR(drv->layers)) {
                dev_err(drm->dev, "Couldn't create the planes\n");
-               ret = -EINVAL;
+               ret = PTR_ERR(drv->layers);
                goto free_drm;
        }
 
index c3ff10f559cc4811755f764d6ebbfd999a8ee7e9..d198ad7e53234794b0e78933ff395b38b90cfd59 100644 (file)
@@ -152,15 +152,13 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
 
        DRM_DEBUG_DRIVER("Enabling RGB output\n");
 
-       if (!IS_ERR(tcon->panel)) {
+       if (!IS_ERR(tcon->panel))
                drm_panel_prepare(tcon->panel);
-               drm_panel_enable(tcon->panel);
-       }
-
-       /* encoder->bridge can be NULL; drm_bridge_enable checks for it */
-       drm_bridge_enable(encoder->bridge);
 
        sun4i_tcon_channel_enable(tcon, 0);
+
+       if (!IS_ERR(tcon->panel))
+               drm_panel_enable(tcon->panel);
 }
 
 static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
@@ -171,15 +169,13 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
 
        DRM_DEBUG_DRIVER("Disabling RGB output\n");
 
-       sun4i_tcon_channel_disable(tcon, 0);
+       if (!IS_ERR(tcon->panel))
+               drm_panel_disable(tcon->panel);
 
-       /* encoder->bridge can be NULL; drm_bridge_disable checks for it */
-       drm_bridge_disable(encoder->bridge);
+       sun4i_tcon_channel_disable(tcon, 0);
 
-       if (!IS_ERR(tcon->panel)) {
-               drm_panel_disable(tcon->panel);
+       if (!IS_ERR(tcon->panel))
                drm_panel_unprepare(tcon->panel);
-       }
 }
 
 static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
index 29f0207fa677064dc4b7bd93ea360fd5d3f414a4..873f010d9616f702deb3d59947831c28a899b853 100644 (file)
@@ -98,17 +98,23 @@ success:
 static int udl_select_std_channel(struct udl_device *udl)
 {
        int ret;
-       u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7,
-                           0x1C, 0x88, 0x5E, 0x15,
-                           0x60, 0xFE, 0xC6, 0x97,
-                           0x16, 0x3D, 0x47, 0xF2};
+       static const u8 set_def_chn[] = {0x57, 0xCD, 0xDC, 0xA7,
+                                        0x1C, 0x88, 0x5E, 0x15,
+                                        0x60, 0xFE, 0xC6, 0x97,
+                                        0x16, 0x3D, 0x47, 0xF2};
+       void *sendbuf;
+
+       sendbuf = kmemdup(set_def_chn, sizeof(set_def_chn), GFP_KERNEL);
+       if (!sendbuf)
+               return -ENOMEM;
 
        ret = usb_control_msg(udl->udev,
                              usb_sndctrlpipe(udl->udev, 0),
                              NR_USB_REQUEST_CHANNEL,
                              (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
-                             set_def_chn, sizeof(set_def_chn),
+                             sendbuf, sizeof(set_def_chn),
                              USB_CTRL_SET_TIMEOUT);
+       kfree(sendbuf);
        return ret < 0 ? ret : 0;
 }
 
index 7e2a12c4fed2a49bb5f35714e8ef42f24cf8f7d1..1a3ad769f8c85bc0506741d105669dd66013b533 100644 (file)
@@ -241,8 +241,8 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
        down_read(&current->mm->mmap_sem);
        ret = get_user_pages((unsigned long)xfer->mem_addr,
                             vsg->num_pages,
-                            (vsg->direction == DMA_FROM_DEVICE),
-                            0, vsg->pages, NULL);
+                            (vsg->direction == DMA_FROM_DEVICE) ? FOLL_WRITE : 0,
+                            vsg->pages, NULL);
 
        up_read(&current->mm->mmap_sem);
        if (ret != vsg->num_pages) {
index 7cf3678623c3a1b0254b88b76d8f8ad95f7a08ce..58048709c34e6ca0f48b03b3bc5638a3b93d7226 100644 (file)
@@ -338,8 +338,7 @@ static void vgdev_atomic_commit_tail(struct drm_atomic_state *state)
 
        drm_atomic_helper_commit_modeset_disables(dev, state);
        drm_atomic_helper_commit_modeset_enables(dev, state);
-       drm_atomic_helper_commit_planes(dev, state,
-                                       DRM_PLANE_COMMIT_ACTIVE_ONLY);
+       drm_atomic_helper_commit_planes(dev, state, 0);
 
        drm_atomic_helper_commit_hw_done(state);
 
index e8ae3dc476d16fb756fd5ec4380fe644f1f858d0..18061a4bc2f287f9d99debc461a22bcd9c9f3c4d 100644 (file)
@@ -241,15 +241,15 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
                              void *ptr);
 
 MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev");
-module_param_named(enable_fbdev, enable_fbdev, int, 0600);
+module_param_named(enable_fbdev, enable_fbdev, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(force_dma_api, "Force using the DMA API for TTM pages");
-module_param_named(force_dma_api, vmw_force_iommu, int, 0600);
+module_param_named(force_dma_api, vmw_force_iommu, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages");
-module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600);
+module_param_named(restrict_iommu, vmw_restrict_iommu, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages");
-module_param_named(force_coherent, vmw_force_coherent, int, 0600);
+module_param_named(force_coherent, vmw_force_coherent, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU");
-module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600);
+module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes");
 module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600);
 
index 070d750af16d33022f8b3496f38d3667d77169ca..1e59a486bba8a65577bc24464e4ea441731049c4 100644 (file)
@@ -43,7 +43,7 @@
 
 #define VMWGFX_DRIVER_DATE "20160210"
 #define VMWGFX_DRIVER_MAJOR 2
-#define VMWGFX_DRIVER_MINOR 10
+#define VMWGFX_DRIVER_MINOR 11
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
index dc5beff2b4aaff83c18dc77187647102efea5266..c7b53d987f06c923c53eaafb0fccdd9631ba72a7 100644 (file)
 
 #define VMW_RES_HT_ORDER 12
 
+/**
+ * enum vmw_resource_relocation_type - Relocation type for resources
+ *
+ * @vmw_res_rel_normal: Traditional relocation. The resource id in the
+ * command stream is replaced with the actual id after validation.
+ * @vmw_res_rel_nop: NOP relocation. The command is unconditionally replaced
+ * with a NOP.
+ * @vmw_res_rel_cond_nop: Conditional NOP relocation. If the resource id
+ * after validation is -1, the command is replaced with a NOP. Otherwise no
+ * action.
+ */
+enum vmw_resource_relocation_type {
+       vmw_res_rel_normal,
+       vmw_res_rel_nop,
+       vmw_res_rel_cond_nop,
+       vmw_res_rel_max
+};
+
 /**
  * struct vmw_resource_relocation - Relocation info for resources
  *
  * @head: List head for the software context's relocation list.
  * @res: Non-ref-counted pointer to the resource.
- * @offset: Offset of 4 byte entries into the command buffer where the
+ * @offset: Offset of single byte entries into the command buffer where the
  * id that needs fixup is located.
+ * @rel_type: Type of relocation.
  */
 struct vmw_resource_relocation {
        struct list_head head;
        const struct vmw_resource *res;
-       unsigned long offset;
+       u32 offset:29;
+       enum vmw_resource_relocation_type rel_type:3;
 };
 
 /**
@@ -109,7 +129,18 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
                                   struct vmw_dma_buffer *vbo,
                                   bool validate_as_mob,
                                   uint32_t *p_val_node);
-
+/**
+ * vmw_ptr_diff - Compute the offset from a to b in bytes
+ *
+ * @a: A starting pointer.
+ * @b: A pointer offset in the same address space.
+ *
+ * Returns: The offset in bytes between the two pointers.
+ */
+static size_t vmw_ptr_diff(void *a, void *b)
+{
+       return (unsigned long) b - (unsigned long) a;
+}
 
 /**
  * vmw_resources_unreserve - unreserve resources previously reserved for
@@ -409,11 +440,14 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
  * @list: Pointer to head of relocation list.
  * @res: The resource.
  * @offset: Offset into the command buffer currently being parsed where the
- * id that needs fixup is located. Granularity is 4 bytes.
+ * id that needs fixup is located. Granularity is one byte.
+ * @rel_type: Relocation type.
  */
 static int vmw_resource_relocation_add(struct list_head *list,
                                       const struct vmw_resource *res,
-                                      unsigned long offset)
+                                      unsigned long offset,
+                                      enum vmw_resource_relocation_type
+                                      rel_type)
 {
        struct vmw_resource_relocation *rel;
 
@@ -425,6 +459,7 @@ static int vmw_resource_relocation_add(struct list_head *list,
 
        rel->res = res;
        rel->offset = offset;
+       rel->rel_type = rel_type;
        list_add_tail(&rel->head, list);
 
        return 0;
@@ -459,11 +494,24 @@ static void vmw_resource_relocations_apply(uint32_t *cb,
 {
        struct vmw_resource_relocation *rel;
 
+       /* Validate the struct vmw_resource_relocation member size */
+       BUILD_BUG_ON(SVGA_CB_MAX_SIZE >= (1 << 29));
+       BUILD_BUG_ON(vmw_res_rel_max >= (1 << 3));
+
        list_for_each_entry(rel, list, head) {
-               if (likely(rel->res != NULL))
-                       cb[rel->offset] = rel->res->id;
-               else
-                       cb[rel->offset] = SVGA_3D_CMD_NOP;
+               u32 *addr = (u32 *)((unsigned long) cb + rel->offset);
+               switch (rel->rel_type) {
+               case vmw_res_rel_normal:
+                       *addr = rel->res->id;
+                       break;
+               case vmw_res_rel_nop:
+                       *addr = SVGA_3D_CMD_NOP;
+                       break;
+               default:
+                       if (rel->res->id == -1)
+                               *addr = SVGA_3D_CMD_NOP;
+                       break;
+               }
        }
 }
 
@@ -655,7 +703,9 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,
        *p_val = NULL;
        ret = vmw_resource_relocation_add(&sw_context->res_relocations,
                                          res,
-                                         id_loc - sw_context->buf_start);
+                                         vmw_ptr_diff(sw_context->buf_start,
+                                                      id_loc),
+                                         vmw_res_rel_normal);
        if (unlikely(ret != 0))
                return ret;
 
@@ -721,7 +771,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
 
                return vmw_resource_relocation_add
                        (&sw_context->res_relocations, res,
-                        id_loc - sw_context->buf_start);
+                        vmw_ptr_diff(sw_context->buf_start, id_loc),
+                        vmw_res_rel_normal);
        }
 
        ret = vmw_user_resource_lookup_handle(dev_priv,
@@ -2143,10 +2194,10 @@ static int vmw_cmd_shader_define(struct vmw_private *dev_priv,
                return ret;
 
        return vmw_resource_relocation_add(&sw_context->res_relocations,
-                                          NULL, &cmd->header.id -
-                                          sw_context->buf_start);
-
-       return 0;
+                                          NULL,
+                                          vmw_ptr_diff(sw_context->buf_start,
+                                                       &cmd->header.id),
+                                          vmw_res_rel_nop);
 }
 
 /**
@@ -2188,10 +2239,10 @@ static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv,
                return ret;
 
        return vmw_resource_relocation_add(&sw_context->res_relocations,
-                                          NULL, &cmd->header.id -
-                                          sw_context->buf_start);
-
-       return 0;
+                                          NULL,
+                                          vmw_ptr_diff(sw_context->buf_start,
+                                                       &cmd->header.id),
+                                          vmw_res_rel_nop);
 }
 
 /**
@@ -2848,8 +2899,7 @@ static int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv,
  * @header: Pointer to the command header in the command stream.
  *
  * Check that the view exists, and if it was not created using this
- * command batch, make sure it's validated (present in the device) so that
- * the remove command will not confuse the device.
+ * command batch, conditionally make this command a NOP.
  */
 static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
                                  struct vmw_sw_context *sw_context,
@@ -2877,10 +2927,16 @@ static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
                return ret;
 
        /*
-        * Add view to the validate list iff it was not created using this
-        * command batch.
+        * If the view wasn't created during this command batch, it might
+        * have been removed due to a context swapout, so add a
+        * relocation to conditionally make this command a NOP to avoid
+        * device errors.
         */
-       return vmw_view_res_val_add(sw_context, view);
+       return vmw_resource_relocation_add(&sw_context->res_relocations,
+                                          view,
+                                          vmw_ptr_diff(sw_context->buf_start,
+                                                       &cmd->header.id),
+                                          vmw_res_rel_cond_nop);
 }
 
 /**
@@ -3029,6 +3085,35 @@ static int vmw_cmd_dx_genmips(struct vmw_private *dev_priv,
                                   cmd->body.shaderResourceViewId);
 }
 
+/**
+ * vmw_cmd_dx_transfer_from_buffer -
+ * Validate an SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_transfer_from_buffer(struct vmw_private *dev_priv,
+                                          struct vmw_sw_context *sw_context,
+                                          SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXTransferFromBuffer body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+       int ret;
+
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                               user_surface_converter,
+                               &cmd->body.srcSid, NULL);
+       if (ret != 0)
+               return ret;
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.destSid, NULL);
+}
+
 static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
                                struct vmw_sw_context *sw_context,
                                void *buf, uint32_t *size)
@@ -3379,6 +3464,9 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
                    &vmw_cmd_buffer_copy_check, true, false, true),
        VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION,
                    &vmw_cmd_pred_copy_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER,
+                   &vmw_cmd_dx_transfer_from_buffer,
+                   true, false, true),
 };
 
 static int vmw_cmd_check(struct vmw_private *dev_priv,
@@ -3848,14 +3936,14 @@ static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv,
        int ret;
 
        *header = NULL;
-       if (!dev_priv->cman || kernel_commands)
-               return kernel_commands;
-
        if (command_size > SVGA_CB_MAX_SIZE) {
                DRM_ERROR("Command buffer is too large.\n");
                return ERR_PTR(-EINVAL);
        }
 
+       if (!dev_priv->cman || kernel_commands)
+               return kernel_commands;
+
        /* If possible, add a little space for fencing. */
        cmdbuf_size = command_size + 512;
        cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE);
@@ -4232,9 +4320,6 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
        ttm_bo_unref(&query_val.bo);
        ttm_bo_unref(&pinned_val.bo);
        vmw_dmabuf_unreference(&dev_priv->pinned_bo);
-       DRM_INFO("Dummy query bo pin count: %d\n",
-                dev_priv->dummy_query_bo->pin_count);
-
 out_unlock:
        return;
 
index 6a328d507a285e027bf9f355b2f5cb9b9a6da8c7..52ca1c9d070ee734f3ce80c516bd3bed3f087252 100644 (file)
@@ -574,10 +574,8 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo,
                bool nonblock = !!(flags & drm_vmw_synccpu_dontblock);
                long lret;
 
-               if (nonblock)
-                       return reservation_object_test_signaled_rcu(bo->resv, true) ? 0 : -EBUSY;
-
-               lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, MAX_SCHEDULE_TIMEOUT);
+               lret = reservation_object_wait_timeout_rcu(bo->resv, true, true,
+                                       nonblock ? 0 : MAX_SCHEDULE_TIMEOUT);
                if (!lret)
                        return -EBUSY;
                else if (lret < 0)
index c2a721a8cef9d99f9e4fe28032eb150ae4d5f472..b445ce9b9757861ecc1ece1071f1c8c3a02a166f 100644 (file)
@@ -324,7 +324,7 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res)
        if (res->id != -1) {
 
                cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size());
-               if (unlikely(cmd == NULL)) {
+               if (unlikely(!cmd)) {
                        DRM_ERROR("Failed reserving FIFO space for surface "
                                  "destruction.\n");
                        return;
@@ -397,7 +397,7 @@ static int vmw_legacy_srf_create(struct vmw_resource *res)
 
        submit_size = vmw_surface_define_size(srf);
        cmd = vmw_fifo_reserve(dev_priv, submit_size);
-       if (unlikely(cmd == NULL)) {
+       if (unlikely(!cmd)) {
                DRM_ERROR("Failed reserving FIFO space for surface "
                          "creation.\n");
                ret = -ENOMEM;
@@ -446,11 +446,10 @@ static int vmw_legacy_srf_dma(struct vmw_resource *res,
        uint8_t *cmd;
        struct vmw_private *dev_priv = res->dev_priv;
 
-       BUG_ON(val_buf->bo == NULL);
-
+       BUG_ON(!val_buf->bo);
        submit_size = vmw_surface_dma_size(srf);
        cmd = vmw_fifo_reserve(dev_priv, submit_size);
-       if (unlikely(cmd == NULL)) {
+       if (unlikely(!cmd)) {
                DRM_ERROR("Failed reserving FIFO space for surface "
                          "DMA.\n");
                return -ENOMEM;
@@ -538,7 +537,7 @@ static int vmw_legacy_srf_destroy(struct vmw_resource *res)
 
        submit_size = vmw_surface_destroy_size();
        cmd = vmw_fifo_reserve(dev_priv, submit_size);
-       if (unlikely(cmd == NULL)) {
+       if (unlikely(!cmd)) {
                DRM_ERROR("Failed reserving FIFO space for surface "
                          "eviction.\n");
                return -ENOMEM;
@@ -578,7 +577,7 @@ static int vmw_surface_init(struct vmw_private *dev_priv,
        int ret;
        struct vmw_resource *res = &srf->res;
 
-       BUG_ON(res_free == NULL);
+       BUG_ON(!res_free);
        if (!dev_priv->has_mob)
                vmw_fifo_resource_inc(dev_priv);
        ret = vmw_resource_init(dev_priv, res, true, res_free,
@@ -700,7 +699,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        struct drm_vmw_surface_create_req *req = &arg->req;
        struct drm_vmw_surface_arg *rep = &arg->rep;
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
-       struct drm_vmw_size __user *user_sizes;
        int ret;
        int i, j;
        uint32_t cur_bo_offset;
@@ -748,7 +746,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        }
 
        user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
-       if (unlikely(user_srf == NULL)) {
+       if (unlikely(!user_srf)) {
                ret = -ENOMEM;
                goto out_no_user_srf;
        }
@@ -763,29 +761,21 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels));
        srf->num_sizes = num_sizes;
        user_srf->size = size;
-
-       srf->sizes = kmalloc(srf->num_sizes * sizeof(*srf->sizes), GFP_KERNEL);
-       if (unlikely(srf->sizes == NULL)) {
-               ret = -ENOMEM;
+       srf->sizes = memdup_user((struct drm_vmw_size __user *)(unsigned long)
+                                req->size_addr,
+                                sizeof(*srf->sizes) * srf->num_sizes);
+       if (IS_ERR(srf->sizes)) {
+               ret = PTR_ERR(srf->sizes);
                goto out_no_sizes;
        }
-       srf->offsets = kmalloc(srf->num_sizes * sizeof(*srf->offsets),
-                              GFP_KERNEL);
-       if (unlikely(srf->offsets == NULL)) {
+       srf->offsets = kmalloc_array(srf->num_sizes,
+                                    sizeof(*srf->offsets),
+                                    GFP_KERNEL);
+       if (unlikely(!srf->offsets)) {
                ret = -ENOMEM;
                goto out_no_offsets;
        }
 
-       user_sizes = (struct drm_vmw_size __user *)(unsigned long)
-           req->size_addr;
-
-       ret = copy_from_user(srf->sizes, user_sizes,
-                            srf->num_sizes * sizeof(*srf->sizes));
-       if (unlikely(ret != 0)) {
-               ret = -EFAULT;
-               goto out_no_copy;
-       }
-
        srf->base_size = *srf->sizes;
        srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
        srf->multisample_count = 0;
@@ -923,7 +913,7 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
 
        ret = -EINVAL;
        base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle);
-       if (unlikely(base == NULL)) {
+       if (unlikely(!base)) {
                DRM_ERROR("Could not find surface to reference.\n");
                goto out_no_lookup;
        }
@@ -1069,7 +1059,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res)
 
        cmd = vmw_fifo_reserve(dev_priv, submit_len);
        cmd2 = (typeof(cmd2))cmd;
-       if (unlikely(cmd == NULL)) {
+       if (unlikely(!cmd)) {
                DRM_ERROR("Failed reserving FIFO space for surface "
                          "creation.\n");
                ret = -ENOMEM;
@@ -1135,7 +1125,7 @@ static int vmw_gb_surface_bind(struct vmw_resource *res,
        submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0);
 
        cmd1 = vmw_fifo_reserve(dev_priv, submit_size);
-       if (unlikely(cmd1 == NULL)) {
+       if (unlikely(!cmd1)) {
                DRM_ERROR("Failed reserving FIFO space for surface "
                          "binding.\n");
                return -ENOMEM;
@@ -1185,7 +1175,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res,
 
        submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2));
        cmd = vmw_fifo_reserve(dev_priv, submit_size);
-       if (unlikely(cmd == NULL)) {
+       if (unlikely(!cmd)) {
                DRM_ERROR("Failed reserving FIFO space for surface "
                          "unbinding.\n");
                return -ENOMEM;
@@ -1244,7 +1234,7 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res)
        vmw_binding_res_list_scrub(&res->binding_head);
 
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
-       if (unlikely(cmd == NULL)) {
+       if (unlikely(!cmd)) {
                DRM_ERROR("Failed reserving FIFO space for surface "
                          "destruction.\n");
                mutex_unlock(&dev_priv->binding_mutex);
@@ -1410,7 +1400,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
 
        user_srf = container_of(base, struct vmw_user_surface, prime.base);
        srf = &user_srf->srf;
-       if (srf->res.backup == NULL) {
+       if (!srf->res.backup) {
                DRM_ERROR("Shared GB surface is missing a backup buffer.\n");
                goto out_bad_resource;
        }
@@ -1524,7 +1514,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev,
        }
 
        user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
-       if (unlikely(user_srf == NULL)) {
+       if (unlikely(!user_srf)) {
                ret = -ENOMEM;
                goto out_no_user_srf;
        }
index 2ba7d437a2afc7a0758402690526de5366abb718..805b6fa7b5f4c2f7ca98582ff028e1268bc66540 100644 (file)
@@ -1617,7 +1617,7 @@ ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
        ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
                                        complete, complete_context);
        if (IS_ERR(ctx))
-               return ERR_PTR(PTR_ERR(ctx));
+               return ERR_CAST(ctx);
 
        run = kzalloc(sizeof(*run), GFP_KERNEL);
        if (!run) {
index 086d8a50715789d2237d19a59d8e24f407d35e23..60d30203a5faf9c7b69dcddb09ec0a086ca96a08 100644 (file)
 #include <linux/usb/ch9.h>
 #include "hid-ids.h"
 
+#define CP2112_REPORT_MAX_LENGTH               64
+#define CP2112_GPIO_CONFIG_LENGTH              5
+#define CP2112_GPIO_GET_LENGTH                 2
+#define CP2112_GPIO_SET_LENGTH                 3
+
 enum {
        CP2112_GPIO_CONFIG              = 0x02,
        CP2112_GPIO_GET                 = 0x03,
@@ -161,6 +166,8 @@ struct cp2112_device {
        atomic_t read_avail;
        atomic_t xfer_avail;
        struct gpio_chip gc;
+       u8 *in_out_buffer;
+       spinlock_t lock;
 };
 
 static int gpio_push_pull = 0xFF;
@@ -171,62 +178,86 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
-       u8 buf[5];
+       u8 *buf = dev->in_out_buffer;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&dev->lock, flags);
+
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
-                                      sizeof(buf), HID_FEATURE_REPORT,
-                                      HID_REQ_GET_REPORT);
-       if (ret != sizeof(buf)) {
+                                CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
+                                HID_REQ_GET_REPORT);
+       if (ret != CP2112_GPIO_CONFIG_LENGTH) {
                hid_err(hdev, "error requesting GPIO config: %d\n", ret);
-               return ret;
+               goto exit;
        }
 
        buf[1] &= ~(1 << offset);
        buf[2] = gpio_push_pull;
 
-       ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf),
-                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+       ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
+                                CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
+                                HID_REQ_SET_REPORT);
        if (ret < 0) {
                hid_err(hdev, "error setting GPIO config: %d\n", ret);
-               return ret;
+               goto exit;
        }
 
-       return 0;
+       ret = 0;
+
+exit:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret <= 0 ? ret : -EIO;
 }
 
 static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
-       u8 buf[3];
+       u8 *buf = dev->in_out_buffer;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&dev->lock, flags);
+
        buf[0] = CP2112_GPIO_SET;
        buf[1] = value ? 0xff : 0;
        buf[2] = 1 << offset;
 
-       ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf, sizeof(buf),
-                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+       ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf,
+                                CP2112_GPIO_SET_LENGTH, HID_FEATURE_REPORT,
+                                HID_REQ_SET_REPORT);
        if (ret < 0)
                hid_err(hdev, "error setting GPIO values: %d\n", ret);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
-       u8 buf[2];
+       u8 *buf = dev->in_out_buffer;
+       unsigned long flags;
        int ret;
 
-       ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf, sizeof(buf),
-                                      HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
-       if (ret != sizeof(buf)) {
+       spin_lock_irqsave(&dev->lock, flags);
+
+       ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf,
+                                CP2112_GPIO_GET_LENGTH, HID_FEATURE_REPORT,
+                                HID_REQ_GET_REPORT);
+       if (ret != CP2112_GPIO_GET_LENGTH) {
                hid_err(hdev, "error requesting GPIO values: %d\n", ret);
-               return ret;
+               ret = ret < 0 ? ret : -EIO;
+               goto exit;
        }
 
-       return (buf[1] >> offset) & 1;
+       ret = (buf[1] >> offset) & 1;
+
+exit:
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return ret;
 }
 
 static int cp2112_gpio_direction_output(struct gpio_chip *chip,
@@ -234,27 +265,33 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
 {
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
-       u8 buf[5];
+       u8 *buf = dev->in_out_buffer;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&dev->lock, flags);
+
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
-                                      sizeof(buf), HID_FEATURE_REPORT,
-                                      HID_REQ_GET_REPORT);
-       if (ret != sizeof(buf)) {
+                                CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
+                                HID_REQ_GET_REPORT);
+       if (ret != CP2112_GPIO_CONFIG_LENGTH) {
                hid_err(hdev, "error requesting GPIO config: %d\n", ret);
-               return ret;
+               goto fail;
        }
 
        buf[1] |= 1 << offset;
        buf[2] = gpio_push_pull;
 
-       ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf),
-                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+       ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
+                                CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
+                                HID_REQ_SET_REPORT);
        if (ret < 0) {
                hid_err(hdev, "error setting GPIO config: %d\n", ret);
-               return ret;
+               goto fail;
        }
 
+       spin_unlock_irqrestore(&dev->lock, flags);
+
        /*
         * Set gpio value when output direction is already set,
         * as specified in AN495, Rev. 0.2, cpt. 4.4
@@ -262,6 +299,10 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
        cp2112_gpio_set(chip, offset, value);
 
        return 0;
+
+fail:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret < 0 ? ret : -EIO;
 }
 
 static int cp2112_hid_get(struct hid_device *hdev, unsigned char report_number,
@@ -1007,6 +1048,17 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct cp2112_smbus_config_report config;
        int ret;
 
+       dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->in_out_buffer = devm_kzalloc(&hdev->dev, CP2112_REPORT_MAX_LENGTH,
+                                         GFP_KERNEL);
+       if (!dev->in_out_buffer)
+               return -ENOMEM;
+
+       spin_lock_init(&dev->lock);
+
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
@@ -1063,12 +1115,6 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto err_power_normal;
        }
 
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               ret = -ENOMEM;
-               goto err_power_normal;
-       }
-
        hid_set_drvdata(hdev, (void *)dev);
        dev->hdev               = hdev;
        dev->adap.owner         = THIS_MODULE;
@@ -1087,7 +1133,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        if (ret) {
                hid_err(hdev, "error registering i2c adapter\n");
-               goto err_free_dev;
+               goto err_power_normal;
        }
 
        hid_dbg(hdev, "adapter registered\n");
@@ -1123,8 +1169,6 @@ err_gpiochip_remove:
        gpiochip_remove(&dev->gc);
 err_free_i2c:
        i2c_del_adapter(&dev->adap);
-err_free_dev:
-       kfree(dev);
 err_power_normal:
        hid_hw_power(hdev, PM_HINT_NORMAL);
 err_hid_close:
@@ -1149,7 +1193,6 @@ static void cp2112_remove(struct hid_device *hdev)
         */
        hid_hw_close(hdev);
        hid_hw_stop(hdev);
-       kfree(dev);
 }
 
 static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report,
index 8fd4bf77f264940ec04631252062e06aafe148c8..818ea7d935333046adc5036d141ffa6cf6be5c40 100644 (file)
@@ -234,58 +234,6 @@ static __u8 pid0011_rdesc_fixed[] = {
        0xC0                /*  End Collection                  */
 };
 
-static __u8 pid0006_rdesc_fixed[] = {
-       0x05, 0x01,        /* Usage Page (Generic Desktop)      */
-       0x09, 0x04,        /* Usage (Joystick)                  */
-       0xA1, 0x01,        /* Collection (Application)          */
-       0xA1, 0x02,        /*   Collection (Logical)            */
-       0x75, 0x08,        /*     Report Size (8)               */
-       0x95, 0x05,        /*     Report Count (5)              */
-       0x15, 0x00,        /*     Logical Minimum (0)           */
-       0x26, 0xFF, 0x00,  /*     Logical Maximum (255)         */
-       0x35, 0x00,        /*     Physical Minimum (0)          */
-       0x46, 0xFF, 0x00,  /*     Physical Maximum (255)        */
-       0x09, 0x30,        /*     Usage (X)                     */
-       0x09, 0x33,        /*     Usage (Ry)                    */
-       0x09, 0x32,        /*     Usage (Z)                     */
-       0x09, 0x31,        /*     Usage (Y)                     */
-       0x09, 0x34,        /*     Usage (Ry)                    */
-       0x81, 0x02,        /*     Input (Variable)              */
-       0x75, 0x04,        /*     Report Size (4)               */
-       0x95, 0x01,        /*     Report Count (1)              */
-       0x25, 0x07,        /*     Logical Maximum (7)           */
-       0x46, 0x3B, 0x01,  /*     Physical Maximum (315)        */
-       0x65, 0x14,        /*     Unit (Centimeter)             */
-       0x09, 0x39,        /*     Usage (Hat switch)            */
-       0x81, 0x42,        /*     Input (Variable)              */
-       0x65, 0x00,        /*     Unit (None)                   */
-       0x75, 0x01,        /*     Report Size (1)               */
-       0x95, 0x0C,        /*     Report Count (12)             */
-       0x25, 0x01,        /*     Logical Maximum (1)           */
-       0x45, 0x01,        /*     Physical Maximum (1)          */
-       0x05, 0x09,        /*     Usage Page (Button)           */
-       0x19, 0x01,        /*     Usage Minimum (0x01)          */
-       0x29, 0x0C,        /*     Usage Maximum (0x0C)          */
-       0x81, 0x02,        /*     Input (Variable)              */
-       0x06, 0x00, 0xFF,  /*     Usage Page (Vendor Defined)   */
-       0x75, 0x01,        /*     Report Size (1)               */
-       0x95, 0x08,        /*     Report Count (8)              */
-       0x25, 0x01,        /*     Logical Maximum (1)           */
-       0x45, 0x01,        /*     Physical Maximum (1)          */
-       0x09, 0x01,        /*     Usage (0x01)                  */
-       0x81, 0x02,        /*     Input (Variable)              */
-       0xC0,              /*   End Collection                  */
-       0xA1, 0x02,        /*   Collection (Logical)            */
-       0x75, 0x08,        /*     Report Size (8)               */
-       0x95, 0x07,        /*     Report Count (7)              */
-       0x46, 0xFF, 0x00,  /*     Physical Maximum (255)        */
-       0x26, 0xFF, 0x00,  /*     Logical Maximum (255)         */
-       0x09, 0x02,        /*     Usage (0x02)                  */
-       0x91, 0x02,        /*     Output (Variable)             */
-       0xC0,              /*   End Collection                  */
-       0xC0               /* End Collection                    */
-};
-
 static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                                unsigned int *rsize)
 {
@@ -296,16 +244,34 @@ static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        *rsize = sizeof(pid0011_rdesc_fixed);
                }
                break;
-       case 0x0006:
-               if (*rsize == sizeof(pid0006_rdesc_fixed)) {
-                       rdesc = pid0006_rdesc_fixed;
-                       *rsize = sizeof(pid0006_rdesc_fixed);
-               }
-               break;
        }
        return rdesc;
 }
 
+#define map_abs(c)      hid_map_usage(hi, usage, bit, max, EV_ABS, (c))
+#define map_rel(c)      hid_map_usage(hi, usage, bit, max, EV_REL, (c))
+
+static int dr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+                           struct hid_field *field, struct hid_usage *usage,
+                           unsigned long **bit, int *max)
+{
+       switch (usage->hid) {
+       /*
+        * revert to the old hid-input behavior where axes
+        * can be randomly assigned when hid->usage is reused.
+        */
+       case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
+       case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
+               if (field->flags & HID_MAIN_ITEM_RELATIVE)
+                       map_rel(usage->hid & 0xf);
+               else
+                       map_abs(usage->hid & 0xf);
+               return 1;
+       }
+
+       return 0;
+}
+
 static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret;
@@ -352,6 +318,7 @@ static struct hid_driver dr_driver = {
        .id_table = dr_devices,
        .report_fixup = dr_report_fixup,
        .probe = dr_probe,
+       .input_mapping = dr_input_mapping,
 };
 module_hid_driver(dr_driver);
 
index cd59c79eebdd2bd896c1ff19d687f25686d7fb35..575aa65436d182c31fb874a432807688747dd785 100644 (file)
@@ -64,6 +64,9 @@
 #define USB_VENDOR_ID_AKAI             0x2011
 #define USB_DEVICE_ID_AKAI_MPKMINI2    0x0715
 
+#define USB_VENDOR_ID_AKAI_09E8                0x09E8
+#define USB_DEVICE_ID_AKAI_09E8_MIDIMIX        0x0031
+
 #define USB_VENDOR_ID_ALCOR            0x058f
 #define USB_DEVICE_ID_ALCOR_USBRS232   0x9720
 
 #define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
 #define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
 #define USB_DEVICE_ID_ATEN_CS682       0x2213
+#define USB_DEVICE_ID_ATEN_CS692       0x8021
 
 #define USB_VENDOR_ID_ATMEL            0x03eb
 #define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
index d8d55f37b4f5604e2d10672513267c483726f05e..d3e1ab162f7c6ade6e2a83053ec1d719f1a08daa 100644 (file)
@@ -100,6 +100,7 @@ struct hidled_device {
        const struct hidled_config *config;
        struct hid_device       *hdev;
        struct hidled_rgb       *rgb;
+       u8                      *buf;
        struct mutex            lock;
 };
 
@@ -118,13 +119,19 @@ static int hidled_send(struct hidled_device *ldev, __u8 *buf)
 
        mutex_lock(&ldev->lock);
 
+       /*
+        * buffer provided to hid_hw_raw_request must not be on the stack
+        * and must not be part of a data structure
+        */
+       memcpy(ldev->buf, buf, ldev->config->report_size);
+
        if (ldev->config->report_type == RAW_REQUEST)
-               ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+               ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf,
                                         ldev->config->report_size,
                                         HID_FEATURE_REPORT,
                                         HID_REQ_SET_REPORT);
        else if (ldev->config->report_type == OUTPUT_REPORT)
-               ret = hid_hw_output_report(ldev->hdev, buf,
+               ret = hid_hw_output_report(ldev->hdev, ldev->buf,
                                           ldev->config->report_size);
        else
                ret = -EINVAL;
@@ -147,17 +154,21 @@ static int hidled_recv(struct hidled_device *ldev, __u8 *buf)
 
        mutex_lock(&ldev->lock);
 
-       ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+       memcpy(ldev->buf, buf, ldev->config->report_size);
+
+       ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf,
                                 ldev->config->report_size,
                                 HID_FEATURE_REPORT,
                                 HID_REQ_SET_REPORT);
        if (ret < 0)
                goto err;
 
-       ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
+       ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf,
                                 ldev->config->report_size,
                                 HID_FEATURE_REPORT,
                                 HID_REQ_GET_REPORT);
+
+       memcpy(buf, ldev->buf, ldev->config->report_size);
 err:
        mutex_unlock(&ldev->lock);
 
@@ -447,6 +458,10 @@ static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (!ldev)
                return -ENOMEM;
 
+       ldev->buf = devm_kmalloc(&hdev->dev, MAX_REPORT_SIZE, GFP_KERNEL);
+       if (!ldev->buf)
+               return -ENOMEM;
+
        ret = hid_parse(hdev);
        if (ret)
                return ret;
index 76f644deb0a75cab6d6810517d4196465be18314..c5c5fbe9d60577f44085d86a7fb5cf60efb6acd3 100644 (file)
@@ -756,11 +756,16 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        /* Setup wireless link with Logitech Wii wheel */
        if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
-               unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+               const unsigned char cbuf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+               u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
 
-               ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
-                                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
 
+               ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
+                                       HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
                if (ret >= 0) {
                        /* insert a little delay of 10 jiffies ~ 40ms */
                        wait_queue_head_t wait;
@@ -772,9 +777,10 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
                        buf[1] = 0xB2;
                        get_random_bytes(&buf[2], 2);
 
-                       ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
+                       ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
                                        HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
                }
+               kfree(buf);
        }
 
        if (drv_data->quirks & LG_FF)
index d6fa496d0ca25c17035233315ba9f5d5ebddc4fd..20b40ad2632503754685b84cc07d8787a4a44515 100644 (file)
@@ -493,7 +493,8 @@ static int magicmouse_input_configured(struct hid_device *hdev,
 static int magicmouse_probe(struct hid_device *hdev,
        const struct hid_device_id *id)
 {
-       __u8 feature[] = { 0xd7, 0x01 };
+       const u8 feature[] = { 0xd7, 0x01 };
+       u8 *buf;
        struct magicmouse_sc *msc;
        struct hid_report *report;
        int ret;
@@ -544,6 +545,12 @@ static int magicmouse_probe(struct hid_device *hdev,
        }
        report->size = 6;
 
+       buf = kmemdup(feature, sizeof(feature), GFP_KERNEL);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err_stop_hw;
+       }
+
        /*
         * Some devices repond with 'invalid report id' when feature
         * report switching it into multitouch mode is sent to it.
@@ -552,8 +559,9 @@ static int magicmouse_probe(struct hid_device *hdev,
         * but there seems to be no other way of switching the mode.
         * Thus the super-ugly hacky success check below.
         */
-       ret = hid_hw_raw_request(hdev, feature[0], feature, sizeof(feature),
+       ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(feature),
                                HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+       kfree(buf);
        if (ret != -EIO && ret != sizeof(feature)) {
                hid_err(hdev, "unable to request touch data (%d)\n", ret);
                goto err_stop_hw;
index 9cd2ca34a6be5583dbcd82a64feb018f66b20bf8..be89bcbf6a71b23f266c8bb0b38b0aa66cca1ae0 100644 (file)
@@ -188,10 +188,16 @@ static int rmi_set_page(struct hid_device *hdev, u8 page)
 static int rmi_set_mode(struct hid_device *hdev, u8 mode)
 {
        int ret;
-       u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode};
+       const u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode};
+       u8 *buf;
 
-       ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, txbuf,
+       buf = kmemdup(txbuf, sizeof(txbuf), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, buf,
                        sizeof(txbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+       kfree(buf);
        if (ret < 0) {
                dev_err(&hdev->dev, "unable to set rmi mode to %d (%d)\n", mode,
                        ret);
index 5614fee82347f34b0ad96d906d800d3de7906052..3a84aaf1418b45c725531903b41e29ae4ce62236 100644 (file)
@@ -292,11 +292,11 @@ static ssize_t show_value(struct device *dev, struct device_attribute *attr,
        bool input = false;
        int value = 0;
 
-       if (sscanf(attr->attr.name, "feature-%d-%x-%s", &index, &usage,
+       if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,
                   name) == 3) {
                feature = true;
                field_index = index + sensor_inst->input_field_count;
-       } else if (sscanf(attr->attr.name, "input-%d-%x-%s", &index, &usage,
+       } else if (sscanf(attr->attr.name, "input-%x-%x-%s", &index, &usage,
                   name) == 3) {
                input = true;
                field_index = index;
@@ -398,7 +398,7 @@ static ssize_t store_value(struct device *dev, struct device_attribute *attr,
        char name[HID_CUSTOM_NAME_LENGTH];
        int value;
 
-       if (sscanf(attr->attr.name, "feature-%d-%x-%s", &index, &usage,
+       if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,
                   name) == 3) {
                field_index = index + sensor_inst->input_field_count;
        } else
index 658a607dc6d9eb1f7c57da3c4afe065e32ffd156..60875625cbdff45725532b92a395fe7f329163ee 100644 (file)
@@ -212,6 +212,7 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
        __s32 value;
        int ret = 0;
 
+       memset(buffer, 0, buffer_size);
        mutex_lock(&data->mutex);
        report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
        if (!report || (field_index >= report->maxfield)) {
@@ -251,6 +252,9 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
        struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
        int report_size;
        int ret = 0;
+       u8 *val_ptr;
+       int buffer_index = 0;
+       int i;
 
        mutex_lock(&data->mutex);
        report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
@@ -271,7 +275,17 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
                goto done_proc;
        }
        ret = min(report_size, buffer_size);
-       memcpy(buffer, report->field[field_index]->value, ret);
+
+       val_ptr = (u8 *)report->field[field_index]->value;
+       for (i = 0; i < report->field[field_index]->report_count; ++i) {
+               if (buffer_index >= ret)
+                       break;
+
+               memcpy(&((u8 *)buffer)[buffer_index], val_ptr,
+                      report->field[field_index]->report_size / 8);
+               val_ptr += sizeof(__s32);
+               buffer_index += (report->field[field_index]->report_size / 8);
+       }
 
 done_proc:
        mutex_unlock(&data->mutex);
index e2517c11e0ee053c68ff27c5f11325bcf601ba2a..0c9ac4d5d85007e52e45c7f2a3c413c304901264 100644 (file)
@@ -637,6 +637,58 @@ eoi:
        return  IRQ_HANDLED;
 }
 
+/**
+ * ish_disable_dma() - disable dma communication between host and ISHFW
+ * @dev: ishtp device pointer
+ *
+ * Clear the dma enable bit and wait for dma inactive.
+ *
+ * Return: 0 for success else error code.
+ */
+static int ish_disable_dma(struct ishtp_device *dev)
+{
+       unsigned int    dma_delay;
+
+       /* Clear the dma enable bit */
+       ish_reg_write(dev, IPC_REG_ISH_RMP2, 0);
+
+       /* wait for dma inactive */
+       for (dma_delay = 0; dma_delay < MAX_DMA_DELAY &&
+               _ish_read_fw_sts_reg(dev) & (IPC_ISH_IN_DMA);
+               dma_delay += 5)
+               mdelay(5);
+
+       if (dma_delay >= MAX_DMA_DELAY) {
+               dev_err(dev->devc,
+                       "Wait for DMA inactive timeout\n");
+               return  -EBUSY;
+       }
+
+       return 0;
+}
+
+/**
+ * ish_wakeup() - wakeup ishfw from waiting-for-host state
+ * @dev: ishtp device pointer
+ *
+ * Set the dma enable bit and send a void message to FW,
+ * it wil wakeup FW from waiting-for-host state.
+ */
+static void ish_wakeup(struct ishtp_device *dev)
+{
+       /* Set dma enable bit */
+       ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
+
+       /*
+        * Send 0 IPC message so that ISH FW wakes up if it was already
+        * asleep.
+        */
+       ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
+
+       /* Flush writes to doorbell and REMAP2 */
+       ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+}
+
 /**
  * _ish_hw_reset() - HW reset
  * @dev: ishtp device pointer
@@ -649,7 +701,6 @@ static int _ish_hw_reset(struct ishtp_device *dev)
 {
        struct pci_dev *pdev = dev->pdev;
        int     rv;
-       unsigned int    dma_delay;
        uint16_t csr;
 
        if (!pdev)
@@ -664,15 +715,8 @@ static int _ish_hw_reset(struct ishtp_device *dev)
                return  -EINVAL;
        }
 
-       /* Now trigger reset to FW */
-       ish_reg_write(dev, IPC_REG_ISH_RMP2, 0);
-
-       for (dma_delay = 0; dma_delay < MAX_DMA_DELAY &&
-               _ish_read_fw_sts_reg(dev) & (IPC_ISH_IN_DMA);
-               dma_delay += 5)
-               mdelay(5);
-
-       if (dma_delay >= MAX_DMA_DELAY) {
+       /* Disable dma communication between FW and host */
+       if (ish_disable_dma(dev)) {
                dev_err(&pdev->dev,
                        "Can't reset - stuck with DMA in-progress\n");
                return  -EBUSY;
@@ -690,16 +734,8 @@ static int _ish_hw_reset(struct ishtp_device *dev)
        csr |= PCI_D0;
        pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
 
-       ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
-
-       /*
-        * Send 0 IPC message so that ISH FW wakes up if it was already
-        * asleep
-        */
-       ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
-
-       /* Flush writes to doorbell and REMAP2 */
-       ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+       /* Now we can enable ISH DMA operation and wakeup ISHFW */
+       ish_wakeup(dev);
 
        return  0;
 }
@@ -758,16 +794,9 @@ static int _ish_ipc_reset(struct ishtp_device *dev)
 int ish_hw_start(struct ishtp_device *dev)
 {
        ish_set_host_rdy(dev);
-       /* After that we can enable ISH DMA operation */
-       ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
 
-       /*
-        * Send 0 IPC message so that ISH FW wakes up if it was already
-        * asleep
-        */
-       ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
-       /* Flush write to doorbell */
-       ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
+       /* After that we can enable ISH DMA operation and wakeup ISHFW */
+       ish_wakeup(dev);
 
        set_host_ready(dev);
 
@@ -876,6 +905,21 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
  */
 void   ish_device_disable(struct ishtp_device *dev)
 {
+       struct pci_dev *pdev = dev->pdev;
+
+       if (!pdev)
+               return;
+
+       /* Disable dma communication between FW and host */
+       if (ish_disable_dma(dev)) {
+               dev_err(&pdev->dev,
+                       "Can't reset - stuck with DMA in-progress\n");
+               return;
+       }
+
+       /* Put ISH to D3hot state for power saving */
+       pci_set_power_state(pdev, PCI_D3hot);
+
        dev->dev_state = ISHTP_DEV_DISABLED;
        ish_clr_host_rdy(dev);
 }
index 42f0beeb09fd4e2ab4fe6ad246f9f21786bf3e3d..20d647d2dd2cbfa5fb57fbc85de236147cf448ab 100644 (file)
@@ -146,7 +146,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
 
        /* request and enable interrupt */
-       ret = request_irq(pdev->irq, ish_irq_handler, IRQF_NO_SUSPEND,
+       ret = request_irq(pdev->irq, ish_irq_handler, IRQF_SHARED,
                          KBUILD_MODNAME, dev);
        if (ret) {
                dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n",
@@ -202,6 +202,7 @@ static void ish_remove(struct pci_dev *pdev)
        kfree(ishtp_dev);
 }
 
+#ifdef CONFIG_PM
 static struct device *ish_resume_device;
 
 /**
@@ -293,7 +294,6 @@ static int ish_resume(struct device *device)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static const struct dev_pm_ops ish_pm_ops = {
        .suspend = ish_suspend,
        .resume = ish_resume,
@@ -301,7 +301,7 @@ static const struct dev_pm_ops ish_pm_ops = {
 #define ISHTP_ISH_PM_OPS       (&ish_pm_ops)
 #else
 #define ISHTP_ISH_PM_OPS       NULL
-#endif
+#endif /* CONFIG_PM */
 
 static struct pci_driver ish_driver = {
        .name = KBUILD_MODNAME,
index 0a0eca5da47d0274cca10822e3b8d6aded20b6c7..e6cfd323babc62d653146730e4d7325ee8a24696 100644 (file)
@@ -56,12 +56,14 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
        { 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_ATEN, USB_DEVICE_ID_ATEN_CS692, 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 4aa3cb63fd41f4506254187608c995e22359aa28..bcd06306f3e894a379603a4216cadab475be6b69 100644 (file)
@@ -314,10 +314,14 @@ static void heartbeat_onchannelcallback(void *context)
        u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
        struct icmsg_negotiate *negop = NULL;
 
-       vmbus_recvpacket(channel, hbeat_txf_buf,
-                        PAGE_SIZE, &recvlen, &requestid);
+       while (1) {
+
+               vmbus_recvpacket(channel, hbeat_txf_buf,
+                                PAGE_SIZE, &recvlen, &requestid);
+
+               if (!recvlen)
+                       break;
 
-       if (recvlen > 0) {
                icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
                                sizeof(struct vmbuspipe_hdr)];
 
index a259e18d22d5b0e3293230e97979a5120d3265fa..0276d2ef06ee5f3d61811b38b77249df1c03f581 100644 (file)
@@ -961,7 +961,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
 {
        int ret = 0;
 
-       dev_set_name(&child_device_obj->device, "vmbus-%pUl",
+       dev_set_name(&child_device_obj->device, "%pUl",
                     child_device_obj->channel->offermsg.offer.if_instance.b);
 
        child_device_obj->device.bus = &hv_bus;
index 98114cef1e43962eb433560700d0103a96ed7050..2fe1828bd10b79fc18f1dfbe1f2e0e9c00e99cd3 100644 (file)
@@ -194,10 +194,10 @@ static struct adm9240_data *adm9240_update_device(struct device *dev)
                 * 0.5'C per two measurement cycles thus ignore possible
                 * but unlikely aliasing error on lsb reading. --Grant
                 */
-               data->temp = ((i2c_smbus_read_byte_data(client,
+               data->temp = (i2c_smbus_read_byte_data(client,
                                        ADM9240_REG_TEMP) << 8) |
                                        i2c_smbus_read_byte_data(client,
-                                       ADM9240_REG_TEMP_CONF)) / 128;
+                                       ADM9240_REG_TEMP_CONF);
 
                for (i = 0; i < 2; i++) { /* read fans */
                        data->fan[i] = i2c_smbus_read_byte_data(client,
@@ -263,7 +263,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *dummy,
                char *buf)
 {
        struct adm9240_data *data = adm9240_update_device(dev);
-       return sprintf(buf, "%d\n", data->temp * 500); /* 9-bit value */
+       return sprintf(buf, "%d\n", data->temp / 128 * 500); /* 9-bit value */
 }
 
 static ssize_t show_max(struct device *dev, struct device_attribute *devattr,
index adae6848ffb2311b46d59a509fb0883e49cfd6e5..a74c075a30ec49608308ddd45715f1addc104c84 100644 (file)
@@ -536,8 +536,10 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
 
                hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups),
                                             GFP_KERNEL);
-               if (!hwdev->groups)
-                       return ERR_PTR(-ENOMEM);
+               if (!hwdev->groups) {
+                       err = -ENOMEM;
+                       goto free_hwmon;
+               }
 
                attrs = __hwmon_create_attrs(dev, drvdata, chip);
                if (IS_ERR(attrs)) {
index bef84e08597307893b699a854b7d97b94dca234c..c1b9275978f9d9ee9172e99e569de7dca48b491d 100644 (file)
@@ -268,11 +268,13 @@ static int max31790_read_pwm(struct device *dev, u32 attr, int channel,
                             long *val)
 {
        struct max31790_data *data = max31790_update_device(dev);
-       u8 fan_config = data->fan_config[channel];
+       u8 fan_config;
 
        if (IS_ERR(data))
                return PTR_ERR(data);
 
+       fan_config = data->fan_config[channel];
+
        switch (attr) {
        case hwmon_pwm_input:
                *val = data->pwm[channel] >> 8;
index d223650a97e426e582b2cfb58db3ecaedcf7cd4a..11edabf425ae34aac0b72d7c2811c714fa5796f2 100644 (file)
@@ -59,7 +59,6 @@ config I2C_CHARDEV
 
 config I2C_MUX
        tristate "I2C bus multiplexing support"
-       depends on HAS_IOMEM
        help
          Say Y here if you want the I2C core to support the ability to
          handle multiplexed I2C bus topologies, by presenting each
index 6d94e2ec5b4f7183734fbd1159db5d7013fa6f74..d252276feadf6b0b05cbe370330ed7cef5a16857 100644 (file)
@@ -79,12 +79,12 @@ config I2C_AMD8111
 
 config I2C_HIX5HD2
        tristate "Hix5hd2 high-speed I2C driver"
-       depends on ARCH_HIX5HD2 || COMPILE_TEST
+       depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
        help
-         Say Y here to include support for high-speed I2C controller in the
-         Hisilicon based hix5hd2 SoCs.
+         Say Y here to include support for the high-speed I2C controller
+         used in HiSilicon hix5hd2 SoCs.
 
-         This driver can also be built as a module.  If so, the module
+         This driver can also be built as a module. If so, the module
          will be called i2c-hix5hd2.
 
 config I2C_I801
@@ -589,10 +589,10 @@ config I2C_IMG
 
 config I2C_IMX
        tristate "IMX I2C interface"
-       depends on ARCH_MXC || ARCH_LAYERSCAPE
+       depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE
        help
          Say Y here if you want to use the IIC bus controller on
-         the Freescale i.MX/MXC or Layerscape processors.
+         the Freescale i.MX/MXC, Layerscape or ColdFire processors.
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-imx.
index 1fe93c43215cf9e5d26385727e7c4f35a7e2fe89..b403fa5ecf4994c538b9b1d005f9658a93a45072 100644 (file)
                                         DW_IC_INTR_TX_ABRT | \
                                         DW_IC_INTR_STOP_DET)
 
-#define DW_IC_STATUS_ACTIVITY          0x1
-#define DW_IC_STATUS_TFE               BIT(2)
-#define DW_IC_STATUS_MST_ACTIVITY      BIT(5)
+#define DW_IC_STATUS_ACTIVITY  0x1
+
+#define DW_IC_SDA_HOLD_RX_SHIFT                16
+#define DW_IC_SDA_HOLD_RX_MASK         GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
 
 #define DW_IC_ERR_TX_ABRT      0x1
 
@@ -420,12 +421,20 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        /* Configure SDA Hold Time if required */
        reg = dw_readl(dev, DW_IC_COMP_VERSION);
        if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
-               if (dev->sda_hold_time) {
-                       dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
-               } else {
+               if (!dev->sda_hold_time) {
                        /* Keep previous hold time setting if no one set it */
                        dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
                }
+               /*
+                * Workaround for avoiding TX arbitration lost in case I2C
+                * slave pulls SDA down "too quickly" after falling egde of
+                * SCL by enabling non-zero SDA RX hold. Specification says it
+                * extends incoming SDA low to high transition while SCL is
+                * high but it apprears to help also above issue.
+                */
+               if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
+                       dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
+               dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
        } else {
                dev_warn(dev->dev,
                        "Hardware too old to adjust SDA hold time.\n");
@@ -467,25 +476,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
 {
        struct i2c_msg *msgs = dev->msgs;
        u32 ic_tar = 0;
-       bool enabled;
-
-       enabled = dw_readl(dev, DW_IC_ENABLE_STATUS) & 1;
-
-       if (enabled) {
-               u32 ic_status;
 
-               /*
-                * Only disable adapter if ic_tar and ic_con can't be
-                * dynamically updated
-                */
-               ic_status = dw_readl(dev, DW_IC_STATUS);
-               if (!dev->dynamic_tar_update_enabled ||
-                   (ic_status & DW_IC_STATUS_MST_ACTIVITY) ||
-                   !(ic_status & DW_IC_STATUS_TFE)) {
-                       __i2c_dw_enable_and_wait(dev, false);
-                       enabled = false;
-               }
-       }
+       /* Disable the adapter */
+       __i2c_dw_enable_and_wait(dev, false);
 
        /* if the slave address is ten bit address, enable 10BITADDR */
        if (dev->dynamic_tar_update_enabled) {
@@ -515,8 +508,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
        /* enforce disabled interrupts (due to HW issues) */
        i2c_dw_disable_int(dev);
 
-       if (!enabled)
-               __i2c_dw_enable(dev, true);
+       /* Enable the adapter */
+       __i2c_dw_enable(dev, true);
 
        /* Clear and enable interrupts */
        dw_readl(dev, DW_IC_CLR_INTR);
@@ -600,7 +593,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
                        if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
 
                                /* avoid rx buffer overrun */
-                               if (rx_limit - dev->rx_outstanding <= 0)
+                               if (dev->rx_outstanding >= dev->rx_fifo_depth)
                                        break;
 
                                dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
@@ -697,8 +690,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
 }
 
 /*
- * Prepare controller for a transaction and start transfer by calling
- * i2c_dw_xfer_init()
+ * Prepare controller for a transaction and call i2c_dw_xfer_msg
  */
 static int
 i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -741,13 +733,23 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
                goto done;
        }
 
+       /*
+        * We must disable the adapter before returning and signaling the end
+        * of the current transfer. Otherwise the hardware might continue
+        * generating interrupts which in turn causes a race condition with
+        * the following transfer.  Needs some more investigation if the
+        * additional interrupts are a hardware bug or this driver doesn't
+        * handle them correctly yet.
+        */
+       __i2c_dw_enable(dev, false);
+
        if (dev->msg_err) {
                ret = dev->msg_err;
                goto done;
        }
 
        /* no error */
-       if (likely(!dev->cmd_err)) {
+       if (likely(!dev->cmd_err && !dev->status)) {
                ret = num;
                goto done;
        }
@@ -757,6 +759,11 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
                ret = i2c_dw_handle_tx_abort(dev);
                goto done;
        }
+
+       if (dev->status)
+               dev_err(dev->dev,
+                       "transfer terminated early - interrupt latency too high?\n");
+
        ret = -EIO;
 
 done:
@@ -877,19 +884,9 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
         */
 
 tx_aborted:
-       if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
-                       || dev->msg_err) {
-               /*
-                * We must disable interruts before returning and signaling
-                * the end of the current transfer. Otherwise the hardware
-                * might continue generating interrupts for non-existent
-                * transfers.
-                */
-               i2c_dw_disable_int(dev);
-               dw_readl(dev, DW_IC_CLR_INTR);
-
+       if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
                complete(&dev->cmd_complete);
-       else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
+       else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
                /* workaround to trigger pending interrupt */
                stat = dw_readl(dev, DW_IC_INTR_MASK);
                i2c_dw_disable_int(dev);
index 9604024e0eb0959e4b77816214eaf3ac939c29ca..50813a24c541d216ee32f53e8b52fbde6ab09b5c 100644 (file)
@@ -347,7 +347,7 @@ static int dc_i2c_probe(struct platform_device *pdev)
 
        ret = i2c_add_adapter(&i2c->adap);
        if (ret < 0) {
-               clk_unprepare(i2c->clk);
+               clk_disable_unprepare(i2c->clk);
                return ret;
        }
 
@@ -368,6 +368,7 @@ static const struct of_device_id dc_i2c_match[] = {
        { .compatible = "cnxt,cx92755-i2c" },
        { },
 };
+MODULE_DEVICE_TABLE(of, dc_i2c_match);
 
 static struct platform_driver dc_i2c_driver = {
        .probe   = dc_i2c_probe,
index 08847e8b899872e2bc1bffd1d0936f63ee4f38d7..eb3627f35d12002776447982d493835fe36dc064 100644 (file)
 #define SMBHSTCFG_HST_EN       1
 #define SMBHSTCFG_SMB_SMI_EN   2
 #define SMBHSTCFG_I2C_EN       4
+#define SMBHSTCFG_SPD_WD       0x10
 
 /* TCO configuration bits for TCOCTL */
 #define TCOCTL_EN              0x0100
@@ -865,9 +866,16 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
                block = 1;
                break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
-               /* NB: page 240 of ICH5 datasheet shows that the R/#W
-                * bit should be cleared here, even when reading */
-               outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
+               /*
+                * NB: page 240 of ICH5 datasheet shows that the R/#W
+                * bit should be cleared here, even when reading.
+                * However if SPD Write Disable is set (Lynx Point and later),
+                * the read will fail if we don't set the R/#W bit.
+                */
+               outb_p(((addr & 0x7f) << 1) |
+                      ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ?
+                       (read_write & 0x01) : 0),
+                      SMBHSTADD(priv));
                if (read_write == I2C_SMBUS_READ) {
                        /* NB: page 240 of ICH5 datasheet also shows
                         * that DATA1 is the cmd field when reading */
@@ -1573,6 +1581,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
                /* Disable SMBus interrupt feature if SMBus using SMI# */
                priv->features &= ~FEATURE_IRQ;
        }
+       if (temp & SMBHSTCFG_SPD_WD)
+               dev_info(&dev->dev, "SPD Write Disable is set\n");
 
        /* Clear special mode bits */
        if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
index 592a8f26a708db4cb331da5906c492f7af06a6a8..47fc1f1acff7db60a6cf909a43f6d443c04ca91e 100644 (file)
@@ -1009,10 +1009,13 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
        rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0);
        rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0);
 
-       if (!gpio_is_valid(rinfo->sda_gpio) ||
-           !gpio_is_valid(rinfo->scl_gpio) ||
-           IS_ERR(i2c_imx->pinctrl_pins_default) ||
-           IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
+       if (rinfo->sda_gpio == -EPROBE_DEFER ||
+           rinfo->scl_gpio == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
+       } else if (!gpio_is_valid(rinfo->sda_gpio) ||
+                  !gpio_is_valid(rinfo->scl_gpio) ||
+                  IS_ERR(i2c_imx->pinctrl_pins_default) ||
+                  IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
                dev_dbg(&pdev->dev, "recovery information incomplete\n");
                return 0;
        }
index b8ea62105f42c99205c1a241176ebb7210a55c08..30132c3957cdc3d2d76e03a5a82511d9b0a27829 100644 (file)
@@ -729,6 +729,7 @@ static const struct of_device_id jz4780_i2c_of_matches[] = {
        { .compatible = "ingenic,jz4780-i2c", },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, jz4780_i2c_of_matches);
 
 static int jz4780_i2c_probe(struct platform_device *pdev)
 {
index 419b54bfc7c77a981b754f87fd1cbd116e5c0672..5e63b17f935d5fb09947498331dd90269a78891a 100644 (file)
@@ -381,9 +381,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
                if (result)
                        return result;
 
-               data[i] = octeon_i2c_data_read(i2c, &result);
-               if (result)
-                       return result;
+               data[i] = octeon_i2c_data_read(i2c);
                if (recv_len && i == 0) {
                        if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
                                return -EPROTO;
index 1db7c835a45454cb03880410745f9563f43945c7..87151ea74acd475a37726fd43fa927f486ddc76e 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c-smbus.h>
 #include <linux/io.h>
-#include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 
@@ -145,9 +144,9 @@ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8
        u64 tmp;
 
        __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c));
-
-       readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp, tmp & SW_TWSI_V,
-                          I2C_OCTEON_EVENT_WAIT, i2c->adap.timeout);
+       do {
+               tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+       } while ((tmp & SW_TWSI_V) != 0);
 }
 
 #define octeon_i2c_ctl_write(i2c, val)                                 \
@@ -164,28 +163,24 @@ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg,
-                                     int *error)
+static inline u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg)
 {
        u64 tmp;
-       int ret;
 
        __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c));
+       do {
+               tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c));
+       } while ((tmp & SW_TWSI_V) != 0);
 
-       ret = readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp,
-                                tmp & SW_TWSI_V, I2C_OCTEON_EVENT_WAIT,
-                                i2c->adap.timeout);
-       if (error)
-               *error = ret;
        return tmp & 0xFF;
 }
 
 #define octeon_i2c_ctl_read(i2c)                                       \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL)
-#define octeon_i2c_data_read(i2c, error)                               \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error)
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL)
+#define octeon_i2c_data_read(i2c)                                      \
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA)
 #define octeon_i2c_stat_read(i2c)                                      \
-       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL)
+       octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
 
 /**
  * octeon_i2c_read_int - read the TWSI_INT register
index 50702c7bb244beec821e4d04e0352c07ee516a21..df220666d62741f15eb4bbf99c960d3ec4a0f444 100644 (file)
@@ -694,6 +694,8 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
        t_calc->div_low--;
        t_calc->div_high--;
 
+       /* Give the tuning value 0, that would not update con register */
+       t_calc->tuning = 0;
        /* Maximum divider supported by hw is 0xffff */
        if (t_calc->div_low > 0xffff) {
                t_calc->div_low = 0xffff;
index 263685c7a5128773f12dfc00bd4ba75324aeee4c..05cf192ef1acae340397d9ff67f942bca6d08d3e 100644 (file)
@@ -105,7 +105,7 @@ struct slimpro_i2c_dev {
        struct mbox_chan *mbox_chan;
        struct mbox_client mbox_client;
        struct completion rd_complete;
-       u8 dma_buffer[I2C_SMBUS_BLOCK_MAX];
+       u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* dma_buffer[0] is used for length */
        u32 *resp_msg;
 };
 
index 2a972ed7aa0df113185b9fb567e76d11638739e4..e29ff37a43bd615bba54a39402c78d5574af0d92 100644 (file)
@@ -426,6 +426,7 @@ static const struct of_device_id xlp9xx_i2c_of_match[] = {
        { .compatible = "netlogic,xlp980-i2c", },
        { /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = {
index 0968f59b6df58690207b182b4fe192d5422e349b..ad17d88d857361663ae98d8faff52a0d9cedbeab 100644 (file)
@@ -358,6 +358,7 @@ static const struct of_device_id xlr_i2c_dt_ids[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(of, xlr_i2c_dt_ids);
 
 static int xlr_i2c_probe(struct platform_device *pdev)
 {
index 5ab67219f71e64a95c926e20b4c45cb1edce68bf..b432b64e307a81740b0ce8a292dc9b80a3921a40 100644 (file)
@@ -1681,6 +1681,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
 static void of_i2c_register_devices(struct i2c_adapter *adap)
 {
        struct device_node *bus, *node;
+       struct i2c_client *client;
 
        /* Only register child devices if the adapter has a node pointer set */
        if (!adap->dev.of_node)
@@ -1695,7 +1696,14 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
        for_each_available_child_of_node(bus, node) {
                if (of_node_test_and_set_flag(node, OF_POPULATED))
                        continue;
-               of_i2c_register_device(adap, node);
+
+               client = of_i2c_register_device(adap, node);
+               if (IS_ERR(client)) {
+                       dev_warn(&adap->dev,
+                                "Failed to create I2C device for %s\n",
+                                node->full_name);
+                       of_node_clear_flag(node, OF_POPULATED);
+               }
        }
 
        of_node_put(bus);
@@ -2171,6 +2179,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
        /* add the driver to the list of i2c drivers in the driver core */
        driver->driver.owner = owner;
        driver->driver.bus = &i2c_bus_type;
+       INIT_LIST_HEAD(&driver->clients);
 
        /* When registration returns, the driver core
         * will have called probe() for all matching-but-unbound devices.
@@ -2181,7 +2190,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 
        pr_debug("driver [%s] registered\n", driver->driver.name);
 
-       INIT_LIST_HEAD(&driver->clients);
        /* Walk the adapters that are already present */
        i2c_for_each_dev(driver, __process_new_driver);
 
@@ -2299,6 +2307,7 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
                if (IS_ERR(client)) {
                        dev_err(&adap->dev, "failed to create client for '%s'\n",
                                 rd->dn->full_name);
+                       of_node_clear_flag(rd->dn, OF_POPULATED);
                        return notifier_from_errno(PTR_ERR(client));
                }
                break;
index e280c8ecc0b59bcb76d6ca56830aa30aea01a2e3..96de9ce5669b64daa0d77cc856e20a9ea589c234 100644 (file)
@@ -63,6 +63,7 @@ config I2C_MUX_PINCTRL
 
 config I2C_MUX_REG
        tristate "Register-based I2C multiplexer"
+       depends on HAS_IOMEM
        help
          If you say yes to this option, support will be included for a
          register based I2C multiplexer. This driver provides access to
index b3893f6282ba5b38920388657d5d1a70129a0148..3e6fe1760d82fc9b654540ef6da6b955ca7daa81 100644 (file)
@@ -69,10 +69,28 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne
                goto err_with_revert;
        }
 
-       p = devm_pinctrl_get_select(adap->dev.parent, priv->bus_name);
+       /*
+        * Check if there are pinctrl states at all. Note: we cant' use
+        * devm_pinctrl_get_select() because we need to distinguish between
+        * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state().
+        */
+       p = devm_pinctrl_get(adap->dev.parent);
        if (IS_ERR(p)) {
                ret = PTR_ERR(p);
-               goto err_with_put;
+               /* continue if just no pinctrl states (e.g. i2c-gpio), otherwise exit */
+               if (ret != -ENODEV)
+                       goto err_with_put;
+       } else {
+               /* there are states. check and use them */
+               struct pinctrl_state *s = pinctrl_lookup_state(p, priv->bus_name);
+
+               if (IS_ERR(s)) {
+                       ret = PTR_ERR(s);
+                       goto err_with_put;
+               }
+               ret = pinctrl_select_state(p, s);
+               if (ret < 0)
+                       goto err_with_put;
        }
 
        priv->chan[new_chan].parent_adap = adap;
index 1091346f2480a6e4c4a79dd1836964894b9c8169..8bc3d36d28379ee9bf834b49d8022a310e55aee4 100644 (file)
@@ -268,9 +268,9 @@ static int pca954x_probe(struct i2c_client *client,
                                /* discard unconfigured channels */
                                break;
                        idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
-                       data->deselect |= (idle_disconnect_pd
-                                          || idle_disconnect_dt) << num;
                }
+               data->deselect |= (idle_disconnect_pd ||
+                                  idle_disconnect_dt) << num;
 
                ret = i2c_mux_add_adapter(muxc, force, num, class);
 
index da3fb069ec5c06dc2bdd99868ee1ad4e114b471a..ce69048c88e98ba9825fbee17e8fd186b94e8d8f 100644 (file)
@@ -743,8 +743,8 @@ static int st_accel_read_raw(struct iio_dev *indio_dev,
 
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_SCALE:
-               *val = 0;
-               *val2 = adata->current_fullscale->gain;
+               *val = adata->current_fullscale->gain / 1000000;
+               *val2 = adata->current_fullscale->gain % 1000000;
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_SAMP_FREQ:
                *val = adata->odr;
@@ -763,9 +763,13 @@ static int st_accel_write_raw(struct iio_dev *indio_dev,
        int err;
 
        switch (mask) {
-       case IIO_CHAN_INFO_SCALE:
-               err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
+       case IIO_CHAN_INFO_SCALE: {
+               int gain;
+
+               gain = val * 1000000 + val2;
+               err = st_sensors_set_fullscale_by_gain(indio_dev, gain);
                break;
+       }
        case IIO_CHAN_INFO_SAMP_FREQ:
                if (val2)
                        return -EINVAL;
index 7edcf32386206cfb391afaa10055e1dff0b3eb72..99c051490effa736e91d978442e5882fbc2a54f6 100644 (file)
@@ -437,6 +437,8 @@ config STX104
 config TI_ADC081C
        tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
        depends on I2C
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        help
          If you say yes here you get support for Texas Instruments ADC081C,
          ADC101C and ADC121C ADC chips.
index bd321b305a0a03a38d2a26ec282eb22e7f37d5b6..ef761a5086304b4b032afa6095e2d9a605128caa 100644 (file)
@@ -213,13 +213,14 @@ static int atlas_check_ec_calibration(struct atlas_data *data)
        struct device *dev = &data->client->dev;
        int ret;
        unsigned int val;
+       __be16  rval;
 
-       ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &val, 2);
+       ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &rval, 2);
        if (ret)
                return ret;
 
-       dev_info(dev, "probe set to K = %d.%.2d", be16_to_cpu(val) / 100,
-                                                be16_to_cpu(val) % 100);
+       val = be16_to_cpu(rval);
+       dev_info(dev, "probe set to K = %d.%.2d", val / 100, val % 100);
 
        ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val);
        if (ret)
index dc33c1dd5191a57aaa8c3c66cdaa75a31866463c..b5beea53d6f6551aba68e570be25deca87d8288c 100644 (file)
@@ -30,26 +30,26 @@ static struct {
        u32 usage_id;
        int unit; /* 0 for default others from HID sensor spec */
        int scale_val0; /* scale, whole number */
-       int scale_val1; /* scale, fraction in micros */
+       int scale_val1; /* scale, fraction in nanos */
 } unit_conversion[] = {
-       {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650},
+       {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650000},
        {HID_USAGE_SENSOR_ACCEL_3D,
                HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
        {HID_USAGE_SENSOR_ACCEL_3D,
-               HID_USAGE_SENSOR_UNITS_G, 9, 806650},
+               HID_USAGE_SENSOR_UNITS_G, 9, 806650000},
 
-       {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453},
+       {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453293},
        {HID_USAGE_SENSOR_GYRO_3D,
                HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0},
        {HID_USAGE_SENSOR_GYRO_3D,
-               HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453},
+               HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453293},
 
-       {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000},
+       {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000000},
        {HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0},
 
-       {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453},
+       {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453293},
        {HID_USAGE_SENSOR_INCLINOMETER_3D,
-               HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453},
+               HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453293},
        {HID_USAGE_SENSOR_INCLINOMETER_3D,
                HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0},
 
@@ -57,7 +57,7 @@ static struct {
        {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0},
 
        {HID_USAGE_SENSOR_PRESSURE, 0, 100, 0},
-       {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000},
+       {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000000},
 };
 
 static int pow_10(unsigned power)
@@ -266,15 +266,15 @@ EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
 /*
  * This fuction applies the unit exponent to the scale.
  * For example:
- * 9.806650 ->exp:2-> val0[980]val1[665000]
- * 9.000806 ->exp:2-> val0[900]val1[80600]
- * 0.174535 ->exp:2-> val0[17]val1[453500]
- * 1.001745 ->exp:0-> val0[1]val1[1745]
- * 1.001745 ->exp:2-> val0[100]val1[174500]
- * 1.001745 ->exp:4-> val0[10017]val1[450000]
- * 9.806650 ->exp:-2-> val0[0]val1[98066]
+ * 9.806650000 ->exp:2-> val0[980]val1[665000000]
+ * 9.000806000 ->exp:2-> val0[900]val1[80600000]
+ * 0.174535293 ->exp:2-> val0[17]val1[453529300]
+ * 1.001745329 ->exp:0-> val0[1]val1[1745329]
+ * 1.001745329 ->exp:2-> val0[100]val1[174532900]
+ * 1.001745329 ->exp:4-> val0[10017]val1[453290000]
+ * 9.806650000 ->exp:-2-> val0[0]val1[98066500]
  */
-static void adjust_exponent_micro(int *val0, int *val1, int scale0,
+static void adjust_exponent_nano(int *val0, int *val1, int scale0,
                                  int scale1, int exp)
 {
        int i;
@@ -285,32 +285,32 @@ static void adjust_exponent_micro(int *val0, int *val1, int scale0,
        if (exp > 0) {
                *val0 = scale0 * pow_10(exp);
                res = 0;
-               if (exp > 6) {
+               if (exp > 9) {
                        *val1 = 0;
                        return;
                }
                for (i = 0; i < exp; ++i) {
-                       x = scale1 / pow_10(5 - i);
+                       x = scale1 / pow_10(8 - i);
                        res += (pow_10(exp - 1 - i) * x);
-                       scale1 = scale1 % pow_10(5 - i);
+                       scale1 = scale1 % pow_10(8 - i);
                }
                *val0 += res;
                        *val1 = scale1 * pow_10(exp);
        } else if (exp < 0) {
                exp = abs(exp);
-               if (exp > 6) {
+               if (exp > 9) {
                        *val0 = *val1 = 0;
                        return;
                }
                *val0 = scale0 / pow_10(exp);
                rem = scale0 % pow_10(exp);
                res = 0;
-               for (i = 0; i < (6 - exp); ++i) {
-                       x = scale1 / pow_10(5 - i);
-                       res += (pow_10(5 - exp - i) * x);
-                       scale1 = scale1 % pow_10(5 - i);
+               for (i = 0; i < (9 - exp); ++i) {
+                       x = scale1 / pow_10(8 - i);
+                       res += (pow_10(8 - exp - i) * x);
+                       scale1 = scale1 % pow_10(8 - i);
                }
-               *val1 = rem * pow_10(6 - exp) + res;
+               *val1 = rem * pow_10(9 - exp) + res;
        } else {
                *val0 = scale0;
                *val1 = scale1;
@@ -332,14 +332,14 @@ int hid_sensor_format_scale(u32 usage_id,
                        unit_conversion[i].unit == attr_info->units) {
                        exp  = hid_sensor_convert_exponent(
                                                attr_info->unit_expo);
-                       adjust_exponent_micro(val0, val1,
+                       adjust_exponent_nano(val0, val1,
                                        unit_conversion[i].scale_val0,
                                        unit_conversion[i].scale_val1, exp);
                        break;
                }
        }
 
-       return IIO_VAL_INT_PLUS_MICRO;
+       return IIO_VAL_INT_PLUS_NANO;
 }
 EXPORT_SYMBOL(hid_sensor_format_scale);
 
index 285a64a589d7137e7c2f188a851e4a36526a2824..975a1f19f74760e5e1c17c786e36d9a86ae5a2a6 100644 (file)
@@ -612,7 +612,7 @@ EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
 ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       int i, len = 0;
+       int i, len = 0, q, r;
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct st_sensor_data *sdata = iio_priv(indio_dev);
 
@@ -621,8 +621,10 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
                if (sdata->sensor_settings->fs.fs_avl[i].num == 0)
                        break;
 
-               len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
-                               sdata->sensor_settings->fs.fs_avl[i].gain);
+               q = sdata->sensor_settings->fs.fs_avl[i].gain / 1000000;
+               r = sdata->sensor_settings->fs.fs_avl[i].gain % 1000000;
+
+               len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ", q, r);
        }
        mutex_unlock(&indio_dev->mlock);
        buf[len - 1] = '\n';
index b98b9d94d184cd058b7ddff7c40e7b9d87f965ac..a97e802ca523138227e9930a585357fd2f873e94 100644 (file)
@@ -335,6 +335,7 @@ static struct platform_driver hid_dev_rot_platform_driver = {
        .id_table = hid_dev_rot_ids,
        .driver = {
                .name   = KBUILD_MODNAME,
+               .pm     = &hid_sensor_pm_ops,
        },
        .probe          = hid_dev_rot_probe,
        .remove         = hid_dev_rot_remove,
index 39dd2026ccc928a7f3c0c1be60948969923594ee..f962f31a5eb223c4f41d273743ed75f30e648a18 100644 (file)
@@ -123,22 +123,26 @@ static int maxim_thermocouple_read(struct maxim_thermocouple_data *data,
 {
        unsigned int storage_bytes = data->chip->read_size;
        unsigned int shift = chan->scan_type.shift + (chan->address * 8);
-       unsigned int buf;
+       __be16 buf16;
+       __be32 buf32;
        int ret;
 
-       ret = spi_read(data->spi, (void *) &buf, storage_bytes);
-       if (ret)
-               return ret;
-
        switch (storage_bytes) {
        case 2:
-               *val = be16_to_cpu(buf);
+               ret = spi_read(data->spi, (void *)&buf16, storage_bytes);
+               *val = be16_to_cpu(buf16);
                break;
        case 4:
-               *val = be32_to_cpu(buf);
+               ret = spi_read(data->spi, (void *)&buf32, storage_bytes);
+               *val = be32_to_cpu(buf32);
                break;
+       default:
+               ret = -EINVAL;
        }
 
+       if (ret)
+               return ret;
+
        /* check to be sure this is a valid reading */
        if (*val & data->chip->status_bit)
                return -EINVAL;
index b136d3acc5bde63f5af8d43f16af3d3107a6db05..0f58f46dbad7e0b4059cbab4ffca95623cad8bb9 100644 (file)
@@ -699,13 +699,16 @@ EXPORT_SYMBOL(rdma_addr_cancel);
 struct resolve_cb_context {
        struct rdma_dev_addr *addr;
        struct completion comp;
+       int status;
 };
 
 static void resolve_cb(int status, struct sockaddr *src_addr,
             struct rdma_dev_addr *addr, void *context)
 {
-       memcpy(((struct resolve_cb_context *)context)->addr, addr, sizeof(struct
-                               rdma_dev_addr));
+       if (!status)
+               memcpy(((struct resolve_cb_context *)context)->addr,
+                      addr, sizeof(struct rdma_dev_addr));
+       ((struct resolve_cb_context *)context)->status = status;
        complete(&((struct resolve_cb_context *)context)->comp);
 }
 
@@ -743,6 +746,10 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
 
        wait_for_completion(&ctx.comp);
 
+       ret = ctx.status;
+       if (ret)
+               return ret;
+
        memcpy(dmac, dev_addr.dst_dev_addr, ETH_ALEN);
        dev = dev_get_by_index(&init_net, dev_addr.bound_dev_if);
        if (!dev)
index c99525512b3434d24a7882d4f869f6e675da44b2..71c7c4c328ef6bb438273395eb9b2d40667e5da3 100644 (file)
@@ -80,6 +80,8 @@ static struct ib_cm {
        __be32 random_id_operand;
        struct list_head timewait_list;
        struct workqueue_struct *wq;
+       /* Sync on cm change port state */
+       spinlock_t state_lock;
 } cm;
 
 /* Counter indexes ordered by attribute ID */
@@ -161,6 +163,8 @@ struct cm_port {
        struct ib_mad_agent *mad_agent;
        struct kobject port_obj;
        u8 port_num;
+       struct list_head cm_priv_prim_list;
+       struct list_head cm_priv_altr_list;
        struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
 };
 
@@ -241,6 +245,12 @@ struct cm_id_private {
        u8 service_timeout;
        u8 target_ack_delay;
 
+       struct list_head prim_list;
+       struct list_head altr_list;
+       /* Indicates that the send port mad is registered and av is set */
+       int prim_send_port_not_ready;
+       int altr_send_port_not_ready;
+
        struct list_head work_list;
        atomic_t work_count;
 };
@@ -259,20 +269,47 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
        struct ib_mad_agent *mad_agent;
        struct ib_mad_send_buf *m;
        struct ib_ah *ah;
+       struct cm_av *av;
+       unsigned long flags, flags2;
+       int ret = 0;
 
+       /* don't let the port to be released till the agent is down */
+       spin_lock_irqsave(&cm.state_lock, flags2);
+       spin_lock_irqsave(&cm.lock, flags);
+       if (!cm_id_priv->prim_send_port_not_ready)
+               av = &cm_id_priv->av;
+       else if (!cm_id_priv->altr_send_port_not_ready &&
+                (cm_id_priv->alt_av.port))
+               av = &cm_id_priv->alt_av;
+       else {
+               pr_info("%s: not valid CM id\n", __func__);
+               ret = -ENODEV;
+               spin_unlock_irqrestore(&cm.lock, flags);
+               goto out;
+       }
+       spin_unlock_irqrestore(&cm.lock, flags);
+       /* Make sure the port haven't released the mad yet */
        mad_agent = cm_id_priv->av.port->mad_agent;
-       ah = ib_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr);
-       if (IS_ERR(ah))
-               return PTR_ERR(ah);
+       if (!mad_agent) {
+               pr_info("%s: not a valid MAD agent\n", __func__);
+               ret = -ENODEV;
+               goto out;
+       }
+       ah = ib_create_ah(mad_agent->qp->pd, &av->ah_attr);
+       if (IS_ERR(ah)) {
+               ret = PTR_ERR(ah);
+               goto out;
+       }
 
        m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
-                              cm_id_priv->av.pkey_index,
+                              av->pkey_index,
                               0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
                               GFP_ATOMIC,
                               IB_MGMT_BASE_VERSION);
        if (IS_ERR(m)) {
                ib_destroy_ah(ah);
-               return PTR_ERR(m);
+               ret = PTR_ERR(m);
+               goto out;
        }
 
        /* Timeout set by caller if response is expected. */
@@ -282,7 +319,10 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
        atomic_inc(&cm_id_priv->refcount);
        m->context[0] = cm_id_priv;
        *msg = m;
-       return 0;
+
+out:
+       spin_unlock_irqrestore(&cm.state_lock, flags2);
+       return ret;
 }
 
 static int cm_alloc_response_msg(struct cm_port *port,
@@ -352,7 +392,8 @@ static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,
                           grh, &av->ah_attr);
 }
 
-static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
+static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av,
+                             struct cm_id_private *cm_id_priv)
 {
        struct cm_device *cm_dev;
        struct cm_port *port = NULL;
@@ -387,7 +428,17 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
                             &av->ah_attr);
        av->timeout = path->packet_life_time + 1;
 
-       return 0;
+       spin_lock_irqsave(&cm.lock, flags);
+       if (&cm_id_priv->av == av)
+               list_add_tail(&cm_id_priv->prim_list, &port->cm_priv_prim_list);
+       else if (&cm_id_priv->alt_av == av)
+               list_add_tail(&cm_id_priv->altr_list, &port->cm_priv_altr_list);
+       else
+               ret = -EINVAL;
+
+       spin_unlock_irqrestore(&cm.lock, flags);
+
+       return ret;
 }
 
 static int cm_alloc_id(struct cm_id_private *cm_id_priv)
@@ -677,6 +728,8 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device,
        spin_lock_init(&cm_id_priv->lock);
        init_completion(&cm_id_priv->comp);
        INIT_LIST_HEAD(&cm_id_priv->work_list);
+       INIT_LIST_HEAD(&cm_id_priv->prim_list);
+       INIT_LIST_HEAD(&cm_id_priv->altr_list);
        atomic_set(&cm_id_priv->work_count, -1);
        atomic_set(&cm_id_priv->refcount, 1);
        return &cm_id_priv->id;
@@ -892,6 +945,15 @@ retest:
                break;
        }
 
+       spin_lock_irq(&cm.lock);
+       if (!list_empty(&cm_id_priv->altr_list) &&
+           (!cm_id_priv->altr_send_port_not_ready))
+               list_del(&cm_id_priv->altr_list);
+       if (!list_empty(&cm_id_priv->prim_list) &&
+           (!cm_id_priv->prim_send_port_not_ready))
+               list_del(&cm_id_priv->prim_list);
+       spin_unlock_irq(&cm.lock);
+
        cm_free_id(cm_id->local_id);
        cm_deref_id(cm_id_priv);
        wait_for_completion(&cm_id_priv->comp);
@@ -1192,12 +1254,13 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
                goto out;
        }
 
-       ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av);
+       ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av,
+                                cm_id_priv);
        if (ret)
                goto error1;
        if (param->alternate_path) {
                ret = cm_init_av_by_path(param->alternate_path,
-                                        &cm_id_priv->alt_av);
+                                        &cm_id_priv->alt_av, cm_id_priv);
                if (ret)
                        goto error1;
        }
@@ -1653,7 +1716,8 @@ static int cm_req_handler(struct cm_work *work)
                        dev_put(gid_attr.ndev);
                }
                work->path[0].gid_type = gid_attr.gid_type;
-               ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
+               ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av,
+                                        cm_id_priv);
        }
        if (ret) {
                int err = ib_get_cached_gid(work->port->cm_dev->ib_device,
@@ -1672,7 +1736,8 @@ static int cm_req_handler(struct cm_work *work)
                goto rejected;
        }
        if (req_msg->alt_local_lid) {
-               ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av);
+               ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av,
+                                        cm_id_priv);
                if (ret) {
                        ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID,
                                       &work->path[0].sgid,
@@ -2727,7 +2792,8 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id,
                goto out;
        }
 
-       ret = cm_init_av_by_path(alternate_path, &cm_id_priv->alt_av);
+       ret = cm_init_av_by_path(alternate_path, &cm_id_priv->alt_av,
+                                cm_id_priv);
        if (ret)
                goto out;
        cm_id_priv->alt_av.timeout =
@@ -2839,7 +2905,8 @@ static int cm_lap_handler(struct cm_work *work)
        cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
                                work->mad_recv_wc->recv_buf.grh,
                                &cm_id_priv->av);
-       cm_init_av_by_path(param->alternate_path, &cm_id_priv->alt_av);
+       cm_init_av_by_path(param->alternate_path, &cm_id_priv->alt_av,
+                          cm_id_priv);
        ret = atomic_inc_and_test(&cm_id_priv->work_count);
        if (!ret)
                list_add_tail(&work->list, &cm_id_priv->work_list);
@@ -3031,7 +3098,7 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id,
                return -EINVAL;
 
        cm_id_priv = container_of(cm_id, struct cm_id_private, id);
-       ret = cm_init_av_by_path(param->path, &cm_id_priv->av);
+       ret = cm_init_av_by_path(param->path, &cm_id_priv->av, cm_id_priv);
        if (ret)
                goto out;
 
@@ -3468,7 +3535,9 @@ out:
 static int cm_migrate(struct ib_cm_id *cm_id)
 {
        struct cm_id_private *cm_id_priv;
+       struct cm_av tmp_av;
        unsigned long flags;
+       int tmp_send_port_not_ready;
        int ret = 0;
 
        cm_id_priv = container_of(cm_id, struct cm_id_private, id);
@@ -3477,7 +3546,14 @@ static int cm_migrate(struct ib_cm_id *cm_id)
            (cm_id->lap_state == IB_CM_LAP_UNINIT ||
             cm_id->lap_state == IB_CM_LAP_IDLE)) {
                cm_id->lap_state = IB_CM_LAP_IDLE;
+               /* Swap address vector */
+               tmp_av = cm_id_priv->av;
                cm_id_priv->av = cm_id_priv->alt_av;
+               cm_id_priv->alt_av = tmp_av;
+               /* Swap port send ready state */
+               tmp_send_port_not_ready = cm_id_priv->prim_send_port_not_ready;
+               cm_id_priv->prim_send_port_not_ready = cm_id_priv->altr_send_port_not_ready;
+               cm_id_priv->altr_send_port_not_ready = tmp_send_port_not_ready;
        } else
                ret = -EINVAL;
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -3888,6 +3964,9 @@ static void cm_add_one(struct ib_device *ib_device)
                port->cm_dev = cm_dev;
                port->port_num = i;
 
+               INIT_LIST_HEAD(&port->cm_priv_prim_list);
+               INIT_LIST_HEAD(&port->cm_priv_altr_list);
+
                ret = cm_create_port_fs(port);
                if (ret)
                        goto error1;
@@ -3945,6 +4024,8 @@ static void cm_remove_one(struct ib_device *ib_device, void *client_data)
 {
        struct cm_device *cm_dev = client_data;
        struct cm_port *port;
+       struct cm_id_private *cm_id_priv;
+       struct ib_mad_agent *cur_mad_agent;
        struct ib_port_modify port_modify = {
                .clr_port_cap_mask = IB_PORT_CM_SUP
        };
@@ -3968,15 +4049,27 @@ static void cm_remove_one(struct ib_device *ib_device, void *client_data)
 
                port = cm_dev->port[i-1];
                ib_modify_port(ib_device, port->port_num, 0, &port_modify);
+               /* Mark all the cm_id's as not valid */
+               spin_lock_irq(&cm.lock);
+               list_for_each_entry(cm_id_priv, &port->cm_priv_altr_list, altr_list)
+                       cm_id_priv->altr_send_port_not_ready = 1;
+               list_for_each_entry(cm_id_priv, &port->cm_priv_prim_list, prim_list)
+                       cm_id_priv->prim_send_port_not_ready = 1;
+               spin_unlock_irq(&cm.lock);
                /*
                 * We flush the queue here after the going_down set, this
                 * verify that no new works will be queued in the recv handler,
                 * after that we can call the unregister_mad_agent
                 */
                flush_workqueue(cm.wq);
-               ib_unregister_mad_agent(port->mad_agent);
+               spin_lock_irq(&cm.state_lock);
+               cur_mad_agent = port->mad_agent;
+               port->mad_agent = NULL;
+               spin_unlock_irq(&cm.state_lock);
+               ib_unregister_mad_agent(cur_mad_agent);
                cm_remove_port_fs(port);
        }
+
        device_unregister(cm_dev->device);
        kfree(cm_dev);
 }
@@ -3989,6 +4082,7 @@ static int __init ib_cm_init(void)
        INIT_LIST_HEAD(&cm.device_list);
        rwlock_init(&cm.device_lock);
        spin_lock_init(&cm.lock);
+       spin_lock_init(&cm.state_lock);
        cm.listen_service_table = RB_ROOT;
        cm.listen_service_id = be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID);
        cm.remote_id_table = RB_ROOT;
index 36bf50ebb187eb40195f0ede0d2d3abcc47d8ccb..2a6fc47a1dfbb578324ada2cd899ed22c4e1c8ad 100644 (file)
@@ -1094,47 +1094,47 @@ static void cma_save_ib_info(struct sockaddr *src_addr,
        }
 }
 
-static void cma_save_ip4_info(struct sockaddr *src_addr,
-                             struct sockaddr *dst_addr,
+static void cma_save_ip4_info(struct sockaddr_in *src_addr,
+                             struct sockaddr_in *dst_addr,
                              struct cma_hdr *hdr,
                              __be16 local_port)
 {
-       struct sockaddr_in *ip4;
-
        if (src_addr) {
-               ip4 = (struct sockaddr_in *)src_addr;
-               ip4->sin_family = AF_INET;
-               ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr;
-               ip4->sin_port = local_port;
+               *src_addr = (struct sockaddr_in) {
+                       .sin_family = AF_INET,
+                       .sin_addr.s_addr = hdr->dst_addr.ip4.addr,
+                       .sin_port = local_port,
+               };
        }
 
        if (dst_addr) {
-               ip4 = (struct sockaddr_in *)dst_addr;
-               ip4->sin_family = AF_INET;
-               ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr;
-               ip4->sin_port = hdr->port;
+               *dst_addr = (struct sockaddr_in) {
+                       .sin_family = AF_INET,
+                       .sin_addr.s_addr = hdr->src_addr.ip4.addr,
+                       .sin_port = hdr->port,
+               };
        }
 }
 
-static void cma_save_ip6_info(struct sockaddr *src_addr,
-                             struct sockaddr *dst_addr,
+static void cma_save_ip6_info(struct sockaddr_in6 *src_addr,
+                             struct sockaddr_in6 *dst_addr,
                              struct cma_hdr *hdr,
                              __be16 local_port)
 {
-       struct sockaddr_in6 *ip6;
-
        if (src_addr) {
-               ip6 = (struct sockaddr_in6 *)src_addr;
-               ip6->sin6_family = AF_INET6;
-               ip6->sin6_addr = hdr->dst_addr.ip6;
-               ip6->sin6_port = local_port;
+               *src_addr = (struct sockaddr_in6) {
+                       .sin6_family = AF_INET6,
+                       .sin6_addr = hdr->dst_addr.ip6,
+                       .sin6_port = local_port,
+               };
        }
 
        if (dst_addr) {
-               ip6 = (struct sockaddr_in6 *)dst_addr;
-               ip6->sin6_family = AF_INET6;
-               ip6->sin6_addr = hdr->src_addr.ip6;
-               ip6->sin6_port = hdr->port;
+               *dst_addr = (struct sockaddr_in6) {
+                       .sin6_family = AF_INET6,
+                       .sin6_addr = hdr->src_addr.ip6,
+                       .sin6_port = hdr->port,
+               };
        }
 }
 
@@ -1159,10 +1159,12 @@ static int cma_save_ip_info(struct sockaddr *src_addr,
 
        switch (cma_get_ip_ver(hdr)) {
        case 4:
-               cma_save_ip4_info(src_addr, dst_addr, hdr, port);
+               cma_save_ip4_info((struct sockaddr_in *)src_addr,
+                                 (struct sockaddr_in *)dst_addr, hdr, port);
                break;
        case 6:
-               cma_save_ip6_info(src_addr, dst_addr, hdr, port);
+               cma_save_ip6_info((struct sockaddr_in6 *)src_addr,
+                                 (struct sockaddr_in6 *)dst_addr, hdr, port);
                break;
        default:
                return -EAFNOSUPPORT;
@@ -2436,6 +2438,18 @@ static int iboe_tos_to_sl(struct net_device *ndev, int tos)
        return 0;
 }
 
+static enum ib_gid_type cma_route_gid_type(enum rdma_network_type network_type,
+                                          unsigned long supported_gids,
+                                          enum ib_gid_type default_gid)
+{
+       if ((network_type == RDMA_NETWORK_IPV4 ||
+            network_type == RDMA_NETWORK_IPV6) &&
+           test_bit(IB_GID_TYPE_ROCE_UDP_ENCAP, &supported_gids))
+               return IB_GID_TYPE_ROCE_UDP_ENCAP;
+
+       return default_gid;
+}
+
 static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
 {
        struct rdma_route *route = &id_priv->id.route;
@@ -2461,6 +2475,8 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
        route->num_paths = 1;
 
        if (addr->dev_addr.bound_dev_if) {
+               unsigned long supported_gids;
+
                ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if);
                if (!ndev) {
                        ret = -ENODEV;
@@ -2484,7 +2500,12 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
 
                route->path_rec->net = &init_net;
                route->path_rec->ifindex = ndev->ifindex;
-               route->path_rec->gid_type = id_priv->gid_type;
+               supported_gids = roce_gid_type_mask_support(id_priv->id.device,
+                                                           id_priv->id.port_num);
+               route->path_rec->gid_type =
+                       cma_route_gid_type(addr->dev_addr.network,
+                                          supported_gids,
+                                          id_priv->gid_type);
        }
        if (!ndev) {
                ret = -ENODEV;
index c68746ce6624cdd7f0fcc9ecd4db851e45c4b497..84b4eff90395e5eb2afc7d66a2f932de8afd28f2 100644 (file)
@@ -94,6 +94,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
        unsigned long dma_attrs = 0;
        struct scatterlist *sg, *sg_list_start;
        int need_release = 0;
+       unsigned int gup_flags = FOLL_WRITE;
 
        if (dmasync)
                dma_attrs |= DMA_ATTR_WRITE_BARRIER;
@@ -174,7 +175,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
 
        cur_base = addr & PAGE_MASK;
 
-       if (npages == 0) {
+       if (npages == 0 || npages > UINT_MAX) {
                ret = -EINVAL;
                goto out;
        }
@@ -183,6 +184,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
        if (ret)
                goto out;
 
+       if (!umem->writable)
+               gup_flags |= FOLL_FORCE;
+
        need_release = 1;
        sg_list_start = umem->sg_head.sgl;
 
@@ -190,7 +194,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
                ret = get_user_pages(cur_base,
                                     min_t(unsigned long, npages,
                                           PAGE_SIZE / sizeof (struct page *)),
-                                    1, !umem->writable, page_list, vma_list);
+                                    gup_flags, page_list, vma_list);
 
                if (ret < 0)
                        goto out;
index 75077a018675e1aa77c7955878250ad521c9d25d..1f0fe3217f2386e03caf4b7e14cd228bddac2020 100644 (file)
@@ -527,6 +527,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
        u64 off;
        int j, k, ret = 0, start_idx, npages = 0;
        u64 base_virt_addr;
+       unsigned int flags = 0;
 
        if (access_mask == 0)
                return -EINVAL;
@@ -556,6 +557,9 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
                goto out_put_task;
        }
 
+       if (access_mask & ODP_WRITE_ALLOWED_BIT)
+               flags |= FOLL_WRITE;
+
        start_idx = (user_virt - ib_umem_start(umem)) >> PAGE_SHIFT;
        k = start_idx;
 
@@ -574,8 +578,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
                 */
                npages = get_user_pages_remote(owning_process, owning_mm,
                                user_virt, gup_num_pages,
-                               access_mask & ODP_WRITE_ALLOWED_BIT,
-                               0, local_page_list, NULL);
+                               flags, local_page_list, NULL);
                up_read(&owning_mm->mmap_sem);
 
                if (npages < 0)
index 0012fa58c105ded78fa433b89024b8ab176aced0..44b1104eb168e50b7d598a2c5f756c5681d1e416 100644 (file)
@@ -262,12 +262,9 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
                        container_of(uobj, struct ib_uqp_object, uevent.uobject);
 
                idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
-               if (qp != qp->real_qp) {
-                       ib_close_qp(qp);
-               } else {
+               if (qp == qp->real_qp)
                        ib_uverbs_detach_umcast(qp, uqp);
-                       ib_destroy_qp(qp);
-               }
+               ib_destroy_qp(qp);
                ib_uverbs_release_uevent(file, &uqp->uevent);
                kfree(uqp);
        }
index 867b8cf82be8eb092f62c464802bedae0c3efe3a..19c6477af19f1416d17c15363e239307542b438d 100644 (file)
@@ -666,18 +666,6 @@ skip_cqe:
        return ret;
 }
 
-static void invalidate_mr(struct c4iw_dev *rhp, u32 rkey)
-{
-       struct c4iw_mr *mhp;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rhp->lock, flags);
-       mhp = get_mhp(rhp, rkey >> 8);
-       if (mhp)
-               mhp->attr.state = 0;
-       spin_unlock_irqrestore(&rhp->lock, flags);
-}
-
 /*
  * Get one cq entry from c4iw and map it to openib.
  *
@@ -733,7 +721,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
                    CQE_OPCODE(&cqe) == FW_RI_SEND_WITH_SE_INV) {
                        wc->ex.invalidate_rkey = CQE_WRID_STAG(&cqe);
                        wc->wc_flags |= IB_WC_WITH_INVALIDATE;
-                       invalidate_mr(qhp->rhp, wc->ex.invalidate_rkey);
+                       c4iw_invalidate_mr(qhp->rhp, wc->ex.invalidate_rkey);
                }
        } else {
                switch (CQE_OPCODE(&cqe)) {
@@ -762,7 +750,8 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
 
                        /* Invalidate the MR if the fastreg failed */
                        if (CQE_STATUS(&cqe) != T4_ERR_SUCCESS)
-                               invalidate_mr(qhp->rhp, CQE_WRID_FR_STAG(&cqe));
+                               c4iw_invalidate_mr(qhp->rhp,
+                                                  CQE_WRID_FR_STAG(&cqe));
                        break;
                default:
                        printk(KERN_ERR MOD "Unexpected opcode %d "
index 7e7f79e5500654f6aa8b1c42b29c20f9491b3c1a..4788e1a46fdee23cce2956cc17ba8d09b0f3eb56 100644 (file)
@@ -999,6 +999,6 @@ extern int db_coalescing_threshold;
 extern int use_dsgl;
 void c4iw_drain_rq(struct ib_qp *qp);
 void c4iw_drain_sq(struct ib_qp *qp);
-
+void c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey);
 
 #endif
index 80e27749420a782b1f7c81b7f08611ea81333835..410408f886c1906a7abdbdbd3178ac9dc541ce3b 100644 (file)
@@ -770,3 +770,15 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
        kfree(mhp);
        return 0;
 }
+
+void c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey)
+{
+       struct c4iw_mr *mhp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rhp->lock, flags);
+       mhp = get_mhp(rhp, rkey >> 8);
+       if (mhp)
+               mhp->attr.state = 0;
+       spin_unlock_irqrestore(&rhp->lock, flags);
+}
index f57deba6717ce69d08b12842ea7ff5fa8514c67a..b7ac97b27c88c2fe11ad11f564ce786085d3217c 100644 (file)
@@ -706,12 +706,8 @@ static int build_memreg(struct t4_sq *sq, union t4_wr *wqe,
        return 0;
 }
 
-static int build_inv_stag(struct c4iw_dev *dev, union t4_wr *wqe,
-                         struct ib_send_wr *wr, u8 *len16)
+static int build_inv_stag(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
 {
-       struct c4iw_mr *mhp = get_mhp(dev, wr->ex.invalidate_rkey >> 8);
-
-       mhp->attr.state = 0;
        wqe->inv.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
        wqe->inv.r2 = 0;
        *len16 = DIV_ROUND_UP(sizeof wqe->inv, 16);
@@ -797,11 +793,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
        spin_lock_irqsave(&qhp->lock, flag);
        if (t4_wq_in_error(&qhp->wq)) {
                spin_unlock_irqrestore(&qhp->lock, flag);
+               *bad_wr = wr;
                return -EINVAL;
        }
        num_wrs = t4_sq_avail(&qhp->wq);
        if (num_wrs == 0) {
                spin_unlock_irqrestore(&qhp->lock, flag);
+               *bad_wr = wr;
                return -ENOMEM;
        }
        while (wr) {
@@ -840,10 +838,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                case IB_WR_RDMA_READ_WITH_INV:
                        fw_opcode = FW_RI_RDMA_READ_WR;
                        swsqe->opcode = FW_RI_READ_REQ;
-                       if (wr->opcode == IB_WR_RDMA_READ_WITH_INV)
+                       if (wr->opcode == IB_WR_RDMA_READ_WITH_INV) {
+                               c4iw_invalidate_mr(qhp->rhp,
+                                                  wr->sg_list[0].lkey);
                                fw_flags = FW_RI_RDMA_READ_INVALIDATE;
-                       else
+                       } else {
                                fw_flags = 0;
+                       }
                        err = build_rdma_read(wqe, wr, &len16);
                        if (err)
                                break;
@@ -876,7 +877,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                fw_flags |= FW_RI_LOCAL_FENCE_FLAG;
                        fw_opcode = FW_RI_INV_LSTAG_WR;
                        swsqe->opcode = FW_RI_LOCAL_INV;
-                       err = build_inv_stag(qhp->rhp, wqe, wr, &len16);
+                       err = build_inv_stag(wqe, wr, &len16);
+                       c4iw_invalidate_mr(qhp->rhp, wr->ex.invalidate_rkey);
                        break;
                default:
                        PDBG("%s post of type=%d TBD!\n", __func__,
@@ -934,11 +936,13 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
        spin_lock_irqsave(&qhp->lock, flag);
        if (t4_wq_in_error(&qhp->wq)) {
                spin_unlock_irqrestore(&qhp->lock, flag);
+               *bad_wr = wr;
                return -EINVAL;
        }
        num_wrs = t4_rq_avail(&qhp->wq);
        if (num_wrs == 0) {
                spin_unlock_irqrestore(&qhp->lock, flag);
+               *bad_wr = wr;
                return -ENOMEM;
        }
        while (wr) {
index a26a9a0bfc417c536ed764499097b5e90c265d78..67ea85a569452e82d037b8e1ee8a3f2567d4f07f 100644 (file)
@@ -775,75 +775,3 @@ void hfi1_put_proc_affinity(int cpu)
        }
        mutex_unlock(&affinity->lock);
 }
-
-int hfi1_set_sdma_affinity(struct hfi1_devdata *dd, const char *buf,
-                          size_t count)
-{
-       struct hfi1_affinity_node *entry;
-       cpumask_var_t mask;
-       int ret, i;
-
-       mutex_lock(&node_affinity.lock);
-       entry = node_affinity_lookup(dd->node);
-
-       if (!entry) {
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       ret = zalloc_cpumask_var(&mask, GFP_KERNEL);
-       if (!ret) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
-
-       ret = cpulist_parse(buf, mask);
-       if (ret)
-               goto out;
-
-       if (!cpumask_subset(mask, cpu_online_mask) || cpumask_empty(mask)) {
-               dd_dev_warn(dd, "Invalid CPU mask\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* reset the SDMA interrupt affinity details */
-       init_cpu_mask_set(&entry->def_intr);
-       cpumask_copy(&entry->def_intr.mask, mask);
-
-       /* Reassign the affinity for each SDMA interrupt. */
-       for (i = 0; i < dd->num_msix_entries; i++) {
-               struct hfi1_msix_entry *msix;
-
-               msix = &dd->msix_entries[i];
-               if (msix->type != IRQ_SDMA)
-                       continue;
-
-               ret = get_irq_affinity(dd, msix);
-
-               if (ret)
-                       break;
-       }
-out:
-       free_cpumask_var(mask);
-unlock:
-       mutex_unlock(&node_affinity.lock);
-       return ret ? ret : strnlen(buf, PAGE_SIZE);
-}
-
-int hfi1_get_sdma_affinity(struct hfi1_devdata *dd, char *buf)
-{
-       struct hfi1_affinity_node *entry;
-
-       mutex_lock(&node_affinity.lock);
-       entry = node_affinity_lookup(dd->node);
-
-       if (!entry) {
-               mutex_unlock(&node_affinity.lock);
-               return -EINVAL;
-       }
-
-       cpumap_print_to_pagebuf(true, buf, &entry->def_intr.mask);
-       mutex_unlock(&node_affinity.lock);
-       return strnlen(buf, PAGE_SIZE);
-}
index b89ea3c0ee1afcd4a3eff2e6916fd9fb0e38d7ca..42e63316afd193f4baf932f0c420eeca52738b39 100644 (file)
@@ -102,10 +102,6 @@ int hfi1_get_proc_affinity(int);
 /* Release a CPU used by a user process. */
 void hfi1_put_proc_affinity(int);
 
-int hfi1_get_sdma_affinity(struct hfi1_devdata *dd, char *buf);
-int hfi1_set_sdma_affinity(struct hfi1_devdata *dd, const char *buf,
-                          size_t count);
-
 struct hfi1_affinity_node {
        int node;
        struct cpu_mask_set def_intr;
index 9bf5f23544d4cf529e67adcd9838fcc1692260bd..24d0820873cf2df220892b9523907aeb9485eb8b 100644 (file)
@@ -6301,19 +6301,8 @@ void set_up_vl15(struct hfi1_devdata *dd, u8 vau, u16 vl15buf)
        /* leave shared count at zero for both global and VL15 */
        write_global_credit(dd, vau, vl15buf, 0);
 
-       /* We may need some credits for another VL when sending packets
-        * with the snoop interface. Dividing it down the middle for VL15
-        * and VL0 should suffice.
-        */
-       if (unlikely(dd->hfi1_snoop.mode_flag == HFI1_PORT_SNOOP_MODE)) {
-               write_csr(dd, SEND_CM_CREDIT_VL15, (u64)(vl15buf >> 1)
-                   << SEND_CM_CREDIT_VL15_DEDICATED_LIMIT_VL_SHIFT);
-               write_csr(dd, SEND_CM_CREDIT_VL, (u64)(vl15buf >> 1)
-                   << SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_SHIFT);
-       } else {
-               write_csr(dd, SEND_CM_CREDIT_VL15, (u64)vl15buf
-                       << SEND_CM_CREDIT_VL15_DEDICATED_LIMIT_VL_SHIFT);
-       }
+       write_csr(dd, SEND_CM_CREDIT_VL15, (u64)vl15buf
+                 << SEND_CM_CREDIT_VL15_DEDICATED_LIMIT_VL_SHIFT);
 }
 
 /*
@@ -9915,9 +9904,6 @@ static void set_lidlmc(struct hfi1_pportdata *ppd)
        u32 mask = ~((1U << ppd->lmc) - 1);
        u64 c1 = read_csr(ppd->dd, DCC_CFG_PORT_CONFIG1);
 
-       if (dd->hfi1_snoop.mode_flag)
-               dd_dev_info(dd, "Set lid/lmc while snooping");
-
        c1 &= ~(DCC_CFG_PORT_CONFIG1_TARGET_DLID_SMASK
                | DCC_CFG_PORT_CONFIG1_DLID_MASK_SMASK);
        c1 |= ((ppd->lid & DCC_CFG_PORT_CONFIG1_TARGET_DLID_MASK)
@@ -12112,7 +12098,7 @@ static void update_synth_timer(unsigned long opaque)
        mod_timer(&dd->synth_stats_timer, jiffies + HZ * SYNTH_CNT_TIME);
 }
 
-#define C_MAX_NAME 13 /* 12 chars + one for /0 */
+#define C_MAX_NAME 16 /* 15 chars + one for /0 */
 static int init_cntrs(struct hfi1_devdata *dd)
 {
        int i, rcv_ctxts, j;
@@ -14463,7 +14449,7 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
         * Any error printing is already done by the init code.
         * On return, we have the chip mapped.
         */
-       ret = hfi1_pcie_ddinit(dd, pdev, ent);
+       ret = hfi1_pcie_ddinit(dd, pdev);
        if (ret < 0)
                goto bail_free;
 
@@ -14691,6 +14677,11 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
        if (ret)
                goto bail_free_cntrs;
 
+       init_completion(&dd->user_comp);
+
+       /* The user refcount starts with one to inidicate an active device */
+       atomic_set(&dd->user_refcount, 1);
+
        goto bail;
 
 bail_free_rcverr:
index 92345259a8f47932faaa45ef16e314c9831fd428..043fd21dc5f3193828ce07da3fa20565c81f8bc0 100644 (file)
 /* DC_DC8051_CFG_MODE.GENERAL bits */
 #define DISABLE_SELF_GUID_CHECK 0x2
 
+/* Bad L2 frame error code */
+#define BAD_L2_ERR      0x6
+
 /*
  * Eager buffer minimum and maximum sizes supported by the hardware.
  * All power-of-two sizes in between are supported as well.
index 6563e4d38b80c141df9d9fd766d5eac9779eb914..c5efff29c1479138ea37e585395eccd17059640b 100644 (file)
@@ -599,7 +599,6 @@ static void __prescan_rxq(struct hfi1_packet *packet)
                                         dd->rhf_offset;
                struct rvt_qp *qp;
                struct ib_header *hdr;
-               struct ib_other_headers *ohdr;
                struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
                u64 rhf = rhf_to_cpu(rhf_addr);
                u32 etype = rhf_rcv_type(rhf), qpn, bth1;
@@ -615,18 +614,21 @@ static void __prescan_rxq(struct hfi1_packet *packet)
                if (etype != RHF_RCV_TYPE_IB)
                        goto next;
 
-               hdr = hfi1_get_msgheader(dd, rhf_addr);
+               packet->hdr = hfi1_get_msgheader(dd, rhf_addr);
+               hdr = packet->hdr;
 
                lnh = be16_to_cpu(hdr->lrh[0]) & 3;
 
-               if (lnh == HFI1_LRH_BTH)
-                       ohdr = &hdr->u.oth;
-               else if (lnh == HFI1_LRH_GRH)
-                       ohdr = &hdr->u.l.oth;
-               else
+               if (lnh == HFI1_LRH_BTH) {
+                       packet->ohdr = &hdr->u.oth;
+               } else if (lnh == HFI1_LRH_GRH) {
+                       packet->ohdr = &hdr->u.l.oth;
+                       packet->rcv_flags |= HFI1_HAS_GRH;
+               } else {
                        goto next; /* just in case */
+               }
 
-               bth1 = be32_to_cpu(ohdr->bth[1]);
+               bth1 = be32_to_cpu(packet->ohdr->bth[1]);
                is_ecn = !!(bth1 & (HFI1_FECN_SMASK | HFI1_BECN_SMASK));
 
                if (!is_ecn)
@@ -646,7 +648,7 @@ static void __prescan_rxq(struct hfi1_packet *packet)
 
                /* turn off BECN, FECN */
                bth1 &= ~(HFI1_FECN_SMASK | HFI1_BECN_SMASK);
-               ohdr->bth[1] = cpu_to_be32(bth1);
+               packet->ohdr->bth[1] = cpu_to_be32(bth1);
 next:
                update_ps_mdata(&mdata, rcd);
        }
@@ -1360,12 +1362,25 @@ int process_receive_ib(struct hfi1_packet *packet)
 
 int process_receive_bypass(struct hfi1_packet *packet)
 {
+       struct hfi1_devdata *dd = packet->rcd->dd;
+
        if (unlikely(rhf_err_flags(packet->rhf)))
                handle_eflags(packet);
 
-       dd_dev_err(packet->rcd->dd,
+       dd_dev_err(dd,
                   "Bypass packets are not supported in normal operation. Dropping\n");
-       incr_cntr64(&packet->rcd->dd->sw_rcv_bypass_packet_errors);
+       incr_cntr64(&dd->sw_rcv_bypass_packet_errors);
+       if (!(dd->err_info_rcvport.status_and_code & OPA_EI_STATUS_SMASK)) {
+               u64 *flits = packet->ebuf;
+
+               if (flits && !(packet->rhf & RHF_LEN_ERR)) {
+                       dd->err_info_rcvport.packet_flit1 = flits[0];
+                       dd->err_info_rcvport.packet_flit2 =
+                               packet->tlen > sizeof(flits[0]) ? flits[1] : 0;
+               }
+               dd->err_info_rcvport.status_and_code |=
+                       (OPA_EI_STATUS_SMASK | BAD_L2_ERR);
+       }
        return RHF_RCV_CONTINUE;
 }
 
index 677efa0e8cd689f167ab72bc13eb2b60dd91b8ed..bd786b7bd30b1256f523a89357e52d12f2a4266c 100644 (file)
@@ -172,6 +172,9 @@ static int hfi1_file_open(struct inode *inode, struct file *fp)
                                               struct hfi1_devdata,
                                               user_cdev);
 
+       if (!atomic_inc_not_zero(&dd->user_refcount))
+               return -ENXIO;
+
        /* Just take a ref now. Not all opens result in a context assign */
        kobject_get(&dd->kobj);
 
@@ -183,11 +186,17 @@ static int hfi1_file_open(struct inode *inode, struct file *fp)
                fd->rec_cpu_num = -1; /* no cpu affinity by default */
                fd->mm = current->mm;
                atomic_inc(&fd->mm->mm_count);
-       }
+               fp->private_data = fd;
+       } else {
+               fp->private_data = NULL;
+
+               if (atomic_dec_and_test(&dd->user_refcount))
+                       complete(&dd->user_comp);
 
-       fp->private_data = fd;
+               return -ENOMEM;
+       }
 
-       return fd ? 0 : -ENOMEM;
+       return 0;
 }
 
 static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
@@ -798,6 +807,10 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
 done:
        mmdrop(fdata->mm);
        kobject_put(&dd->kobj);
+
+       if (atomic_dec_and_test(&dd->user_refcount))
+               complete(&dd->user_comp);
+
        kfree(fdata);
        return 0;
 }
index 7eef11b316ff327e50b8330860db7fd88173ca51..cc87fd4e534bbefd1235be4c010c5df4be9c065c 100644 (file)
@@ -367,26 +367,6 @@ struct hfi1_packet {
        u8 etype;
 };
 
-/*
- * Private data for snoop/capture support.
- */
-struct hfi1_snoop_data {
-       int mode_flag;
-       struct cdev cdev;
-       struct device *class_dev;
-       /* protect snoop data */
-       spinlock_t snoop_lock;
-       struct list_head queue;
-       wait_queue_head_t waitq;
-       void *filter_value;
-       int (*filter_callback)(void *hdr, void *data, void *value);
-       u64 dcc_cfg; /* saved value of DCC Cfg register */
-};
-
-/* snoop mode_flag values */
-#define HFI1_PORT_SNOOP_MODE     1U
-#define HFI1_PORT_CAPTURE_MODE   2U
-
 struct rvt_sge_state;
 
 /*
@@ -613,8 +593,6 @@ struct hfi1_pportdata {
        struct mutex hls_lock;
        u32 host_link_state;
 
-       spinlock_t            sdma_alllock ____cacheline_aligned_in_smp;
-
        u32 lstate;     /* logical link state */
 
        /* these are the "32 bit" regs */
@@ -1104,8 +1082,6 @@ struct hfi1_devdata {
        char *portcntrnames;
        size_t portcntrnameslen;
 
-       struct hfi1_snoop_data hfi1_snoop;
-
        struct err_info_rcvport err_info_rcvport;
        struct err_info_constraint err_info_rcv_constraint;
        struct err_info_constraint err_info_xmit_constraint;
@@ -1141,8 +1117,8 @@ struct hfi1_devdata {
        rhf_rcv_function_ptr normal_rhf_rcv_functions[8];
 
        /*
-        * Handlers for outgoing data so that snoop/capture does not
-        * have to have its hooks in the send path
+        * Capability to have different send engines simply by changing a
+        * pointer value.
         */
        send_routine process_pio_send;
        send_routine process_dma_send;
@@ -1174,6 +1150,10 @@ struct hfi1_devdata {
        spinlock_t aspm_lock;
        /* Number of verbs contexts which have disabled ASPM */
        atomic_t aspm_disabled_cnt;
+       /* Keeps track of user space clients */
+       atomic_t user_refcount;
+       /* Used to wait for outstanding user space clients before dev removal */
+       struct completion user_comp;
 
        struct hfi1_affinity *affinity;
        struct rhashtable sdma_rht;
@@ -1221,8 +1201,6 @@ struct hfi1_devdata *hfi1_lookup(int unit);
 extern u32 hfi1_cpulist_count;
 extern unsigned long *hfi1_cpulist;
 
-extern unsigned int snoop_drop_send;
-extern unsigned int snoop_force_capture;
 int hfi1_init(struct hfi1_devdata *, int);
 int hfi1_count_units(int *npresentp, int *nupp);
 int hfi1_count_active_units(void);
@@ -1557,13 +1535,6 @@ void set_up_vl15(struct hfi1_devdata *dd, u8 vau, u16 vl15buf);
 void reset_link_credits(struct hfi1_devdata *dd);
 void assign_remote_cm_au_table(struct hfi1_devdata *dd, u8 vcu);
 
-int snoop_recv_handler(struct hfi1_packet *packet);
-int snoop_send_dma_handler(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
-                          u64 pbc);
-int snoop_send_pio_handler(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
-                          u64 pbc);
-void snoop_inline_pio_send(struct hfi1_devdata *dd, struct pio_buf *pbuf,
-                          u64 pbc, const void *from, size_t count);
 int set_buffer_control(struct hfi1_pportdata *ppd, struct buffer_control *bc);
 
 static inline struct hfi1_devdata *dd_from_ppd(struct hfi1_pportdata *ppd)
@@ -1763,8 +1734,7 @@ int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len);
 
 int hfi1_pcie_init(struct pci_dev *, const struct pci_device_id *);
 void hfi1_pcie_cleanup(struct pci_dev *);
-int hfi1_pcie_ddinit(struct hfi1_devdata *, struct pci_dev *,
-                    const struct pci_device_id *);
+int hfi1_pcie_ddinit(struct hfi1_devdata *, struct pci_dev *);
 void hfi1_pcie_ddcleanup(struct hfi1_devdata *);
 void hfi1_pcie_flr(struct hfi1_devdata *);
 int pcie_speeds(struct hfi1_devdata *);
@@ -1799,8 +1769,6 @@ int kdeth_process_expected(struct hfi1_packet *packet);
 int kdeth_process_eager(struct hfi1_packet *packet);
 int process_receive_invalid(struct hfi1_packet *packet);
 
-extern rhf_rcv_function_ptr snoop_rhf_rcv_functions[8];
-
 void update_sge(struct rvt_sge_state *ss, u32 length);
 
 /* global module parameter variables */
@@ -1827,9 +1795,6 @@ extern struct mutex hfi1_mutex;
 #define DRIVER_NAME            "hfi1"
 #define HFI1_USER_MINOR_BASE     0
 #define HFI1_TRACE_MINOR         127
-#define HFI1_DIAGPKT_MINOR       128
-#define HFI1_DIAG_MINOR_BASE     129
-#define HFI1_SNOOP_CAPTURE_BASE  200
 #define HFI1_NMINORS             255
 
 #define PCI_VENDOR_ID_INTEL 0x8086
@@ -1848,7 +1813,13 @@ extern struct mutex hfi1_mutex;
 static inline u64 hfi1_pkt_default_send_ctxt_mask(struct hfi1_devdata *dd,
                                                  u16 ctxt_type)
 {
-       u64 base_sc_integrity =
+       u64 base_sc_integrity;
+
+       /* No integrity checks if HFI1_CAP_NO_INTEGRITY is set */
+       if (HFI1_CAP_IS_KSET(NO_INTEGRITY))
+               return 0;
+
+       base_sc_integrity =
        SEND_CTXT_CHECK_ENABLE_DISALLOW_BYPASS_BAD_PKT_LEN_SMASK
        | SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK
        | SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_LONG_BYPASS_PACKETS_SMASK
@@ -1863,7 +1834,6 @@ static inline u64 hfi1_pkt_default_send_ctxt_mask(struct hfi1_devdata *dd,
        | SEND_CTXT_CHECK_ENABLE_CHECK_VL_MAPPING_SMASK
        | SEND_CTXT_CHECK_ENABLE_CHECK_OPCODE_SMASK
        | SEND_CTXT_CHECK_ENABLE_CHECK_SLID_SMASK
-       | SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK
        | SEND_CTXT_CHECK_ENABLE_CHECK_VL_SMASK
        | SEND_CTXT_CHECK_ENABLE_CHECK_ENABLE_SMASK;
 
@@ -1872,18 +1842,23 @@ static inline u64 hfi1_pkt_default_send_ctxt_mask(struct hfi1_devdata *dd,
        else
                base_sc_integrity |= HFI1_PKT_KERNEL_SC_INTEGRITY;
 
-       if (is_ax(dd))
-               /* turn off send-side job key checks - A0 */
-               return base_sc_integrity &
-                      ~SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
+       /* turn on send-side job key checks if !A0 */
+       if (!is_ax(dd))
+               base_sc_integrity |= SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
+
        return base_sc_integrity;
 }
 
 static inline u64 hfi1_pkt_base_sdma_integrity(struct hfi1_devdata *dd)
 {
-       u64 base_sdma_integrity =
+       u64 base_sdma_integrity;
+
+       /* No integrity checks if HFI1_CAP_NO_INTEGRITY is set */
+       if (HFI1_CAP_IS_KSET(NO_INTEGRITY))
+               return 0;
+
+       base_sdma_integrity =
        SEND_DMA_CHECK_ENABLE_DISALLOW_BYPASS_BAD_PKT_LEN_SMASK
-       | SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK
        | SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_LONG_BYPASS_PACKETS_SMASK
        | SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_LONG_IB_PACKETS_SMASK
        | SEND_DMA_CHECK_ENABLE_DISALLOW_BAD_PKT_LEN_SMASK
@@ -1895,14 +1870,18 @@ static inline u64 hfi1_pkt_base_sdma_integrity(struct hfi1_devdata *dd)
        | SEND_DMA_CHECK_ENABLE_CHECK_VL_MAPPING_SMASK
        | SEND_DMA_CHECK_ENABLE_CHECK_OPCODE_SMASK
        | SEND_DMA_CHECK_ENABLE_CHECK_SLID_SMASK
-       | SEND_DMA_CHECK_ENABLE_CHECK_JOB_KEY_SMASK
        | SEND_DMA_CHECK_ENABLE_CHECK_VL_SMASK
        | SEND_DMA_CHECK_ENABLE_CHECK_ENABLE_SMASK;
 
-       if (is_ax(dd))
-               /* turn off send-side job key checks - A0 */
-               return base_sdma_integrity &
-                      ~SEND_DMA_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
+       if (!HFI1_CAP_IS_KSET(STATIC_RATE_CTRL))
+               base_sdma_integrity |=
+               SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK;
+
+       /* turn on send-side job key checks if !A0 */
+       if (!is_ax(dd))
+               base_sdma_integrity |=
+                       SEND_DMA_CHECK_ENABLE_CHECK_JOB_KEY_SMASK;
+
        return base_sdma_integrity;
 }
 
index 60db61536fedf396c7a76dcdf777f7000a189eec..e3b5bc93bc70edd5e253766a6a76db6a13068d4d 100644 (file)
@@ -144,6 +144,8 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
                struct hfi1_ctxtdata *rcd;
 
                ppd = dd->pport + (i % dd->num_pports);
+
+               /* dd->rcd[i] gets assigned inside the callee */
                rcd = hfi1_create_ctxtdata(ppd, i, dd->node);
                if (!rcd) {
                        dd_dev_err(dd,
@@ -169,8 +171,6 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
                if (!rcd->sc) {
                        dd_dev_err(dd,
                                   "Unable to allocate kernel send context, failing\n");
-                       dd->rcd[rcd->ctxt] = NULL;
-                       hfi1_free_ctxtdata(dd, rcd);
                        goto nomem;
                }
 
@@ -178,9 +178,6 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
                if (ret < 0) {
                        dd_dev_err(dd,
                                   "Failed to setup kernel receive context, failing\n");
-                       sc_free(rcd->sc);
-                       dd->rcd[rcd->ctxt] = NULL;
-                       hfi1_free_ctxtdata(dd, rcd);
                        ret = -EFAULT;
                        goto bail;
                }
@@ -196,6 +193,10 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
 nomem:
        ret = -ENOMEM;
 bail:
+       if (dd->rcd) {
+               for (i = 0; i < dd->num_rcv_contexts; ++i)
+                       hfi1_free_ctxtdata(dd, dd->rcd[i]);
+       }
        kfree(dd->rcd);
        dd->rcd = NULL;
        return ret;
@@ -216,7 +217,7 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt,
            dd->num_rcv_contexts - dd->first_user_ctxt)
                kctxt_ngroups = (dd->rcv_entries.nctxt_extra -
                                 (dd->num_rcv_contexts - dd->first_user_ctxt));
-       rcd = kzalloc(sizeof(*rcd), GFP_KERNEL);
+       rcd = kzalloc_node(sizeof(*rcd), GFP_KERNEL, numa);
        if (rcd) {
                u32 rcvtids, max_entries;
 
@@ -261,13 +262,6 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt,
                }
                rcd->eager_base = base * dd->rcv_entries.group_size;
 
-               /* Validate and initialize Rcv Hdr Q variables */
-               if (rcvhdrcnt % HDRQ_INCREMENT) {
-                       dd_dev_err(dd,
-                                  "ctxt%u: header queue count %d must be divisible by %lu\n",
-                                  rcd->ctxt, rcvhdrcnt, HDRQ_INCREMENT);
-                       goto bail;
-               }
                rcd->rcvhdrq_cnt = rcvhdrcnt;
                rcd->rcvhdrqentsize = hfi1_hdrq_entsize;
                /*
@@ -506,7 +500,6 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
        INIT_WORK(&ppd->qsfp_info.qsfp_work, qsfp_event);
 
        mutex_init(&ppd->hls_lock);
-       spin_lock_init(&ppd->sdma_alllock);
        spin_lock_init(&ppd->qsfp_info.qsfp_lock);
 
        ppd->qsfp_info.ppd = ppd;
@@ -1399,28 +1392,43 @@ static void postinit_cleanup(struct hfi1_devdata *dd)
        hfi1_free_devdata(dd);
 }
 
+static int init_validate_rcvhdrcnt(struct device *dev, uint thecnt)
+{
+       if (thecnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) {
+               hfi1_early_err(dev, "Receive header queue count too small\n");
+               return -EINVAL;
+       }
+
+       if (thecnt > HFI1_MAX_HDRQ_EGRBUF_CNT) {
+               hfi1_early_err(dev,
+                              "Receive header queue count cannot be greater than %u\n",
+                              HFI1_MAX_HDRQ_EGRBUF_CNT);
+               return -EINVAL;
+       }
+
+       if (thecnt % HDRQ_INCREMENT) {
+               hfi1_early_err(dev, "Receive header queue count %d must be divisible by %lu\n",
+                              thecnt, HDRQ_INCREMENT);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int ret = 0, j, pidx, initfail;
-       struct hfi1_devdata *dd = ERR_PTR(-EINVAL);
+       struct hfi1_devdata *dd;
        struct hfi1_pportdata *ppd;
 
        /* First, lock the non-writable module parameters */
        HFI1_CAP_LOCK();
 
        /* Validate some global module parameters */
-       if (rcvhdrcnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) {
-               hfi1_early_err(&pdev->dev, "Header queue  count too small\n");
-               ret = -EINVAL;
-               goto bail;
-       }
-       if (rcvhdrcnt > HFI1_MAX_HDRQ_EGRBUF_CNT) {
-               hfi1_early_err(&pdev->dev,
-                              "Receive header queue count cannot be greater than %u\n",
-                              HFI1_MAX_HDRQ_EGRBUF_CNT);
-               ret = -EINVAL;
+       ret = init_validate_rcvhdrcnt(&pdev->dev, rcvhdrcnt);
+       if (ret)
                goto bail;
-       }
+
        /* use the encoding function as a sanitization check */
        if (!encode_rcv_header_entry_size(hfi1_hdrq_entsize)) {
                hfi1_early_err(&pdev->dev, "Invalid HdrQ Entry size %u\n",
@@ -1461,26 +1469,25 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                goto bail;
 
-       /*
-        * Do device-specific initialization, function table setup, dd
-        * allocation, etc.
-        */
-       switch (ent->device) {
-       case PCI_DEVICE_ID_INTEL0:
-       case PCI_DEVICE_ID_INTEL1:
-               dd = hfi1_init_dd(pdev, ent);
-               break;
-       default:
+       if (!(ent->device == PCI_DEVICE_ID_INTEL0 ||
+             ent->device == PCI_DEVICE_ID_INTEL1)) {
                hfi1_early_err(&pdev->dev,
                               "Failing on unknown Intel deviceid 0x%x\n",
                               ent->device);
                ret = -ENODEV;
+               goto clean_bail;
        }
 
-       if (IS_ERR(dd))
+       /*
+        * Do device-specific initialization, function table setup, dd
+        * allocation, etc.
+        */
+       dd = hfi1_init_dd(pdev, ent);
+
+       if (IS_ERR(dd)) {
                ret = PTR_ERR(dd);
-       if (ret)
                goto clean_bail; /* error already printed */
+       }
 
        ret = create_workqueues(dd);
        if (ret)
@@ -1538,12 +1545,31 @@ bail:
        return ret;
 }
 
+static void wait_for_clients(struct hfi1_devdata *dd)
+{
+       /*
+        * Remove the device init value and complete the device if there is
+        * no clients or wait for active clients to finish.
+        */
+       if (atomic_dec_and_test(&dd->user_refcount))
+               complete(&dd->user_comp);
+
+       wait_for_completion(&dd->user_comp);
+}
+
 static void remove_one(struct pci_dev *pdev)
 {
        struct hfi1_devdata *dd = pci_get_drvdata(pdev);
 
        /* close debugfs files before ib unregister */
        hfi1_dbg_ibdev_exit(&dd->verbs_dev);
+
+       /* remove the /dev hfi1 interface */
+       hfi1_device_remove(dd);
+
+       /* wait for existing user space clients to finish */
+       wait_for_clients(dd);
+
        /* unregister from IB core */
        hfi1_unregister_ib_device(dd);
 
@@ -1558,8 +1584,6 @@ static void remove_one(struct pci_dev *pdev)
        /* wait until all of our (qsfp) queue_work() calls complete */
        flush_workqueue(ib_wq);
 
-       hfi1_device_remove(dd);
-
        postinit_cleanup(dd);
 }
 
index 89c68da1c273297c71476fe0acbe37d93f7f97a3..4ac8f330c5cb8bcd02aaee2551441eb6292489d6 100644 (file)
@@ -157,8 +157,7 @@ void hfi1_pcie_cleanup(struct pci_dev *pdev)
  * fields required to re-initialize after a chip reset, or for
  * various other purposes
  */
-int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev,
-                    const struct pci_device_id *ent)
+int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev)
 {
        unsigned long len;
        resource_size_t addr;
index 50a3a36d93632d3e6fbb3a7afced466be2c4547b..d89b8745d4c1c3012e89c8355b3066bb116e26c9 100644 (file)
@@ -668,19 +668,12 @@ void sc_set_cr_threshold(struct send_context *sc, u32 new_threshold)
 void set_pio_integrity(struct send_context *sc)
 {
        struct hfi1_devdata *dd = sc->dd;
-       u64 reg = 0;
        u32 hw_context = sc->hw_context;
        int type = sc->type;
 
-       /*
-        * No integrity checks if HFI1_CAP_NO_INTEGRITY is set, or if
-        * we're snooping.
-        */
-       if (likely(!HFI1_CAP_IS_KSET(NO_INTEGRITY)) &&
-           dd->hfi1_snoop.mode_flag != HFI1_PORT_SNOOP_MODE)
-               reg = hfi1_pkt_default_send_ctxt_mask(dd, type);
-
-       write_kctxt_csr(dd, hw_context, SC(CHECK_ENABLE), reg);
+       write_kctxt_csr(dd, hw_context,
+                       SC(CHECK_ENABLE),
+                       hfi1_pkt_default_send_ctxt_mask(dd, type));
 }
 
 static u32 get_buffers_allocated(struct send_context *sc)
index 8bc5013f39a1ae7ef6f28af82c56017c89edacdb..83198a8a87979baeeb58c591fba0e4d06db6e014 100644 (file)
@@ -89,7 +89,7 @@ void hfi1_add_rnr_timer(struct rvt_qp *qp, u32 to)
 
        lockdep_assert_held(&qp->s_lock);
        qp->s_flags |= RVT_S_WAIT_RNR;
-       qp->s_timer.expires = jiffies + usecs_to_jiffies(to);
+       priv->s_rnr_timer.expires = jiffies + usecs_to_jiffies(to);
        add_timer(&priv->s_rnr_timer);
 }
 
index fd39bcaa062d69683fdbefff9b610f26e15d898b..9cbe52d210778fdce2b3a5ad66d8e06dac801637 100644 (file)
@@ -2009,11 +2009,6 @@ static void sdma_hw_start_up(struct sdma_engine *sde)
        write_sde_csr(sde, SD(ENG_ERR_CLEAR), reg);
 }
 
-#define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \
-(r &= ~SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK)
-
-#define SET_STATIC_RATE_CONTROL_SMASK(r) \
-(r |= SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK)
 /*
  * set_sdma_integrity
  *
@@ -2022,19 +2017,9 @@ static void sdma_hw_start_up(struct sdma_engine *sde)
 static void set_sdma_integrity(struct sdma_engine *sde)
 {
        struct hfi1_devdata *dd = sde->dd;
-       u64 reg;
-
-       if (unlikely(HFI1_CAP_IS_KSET(NO_INTEGRITY)))
-               return;
-
-       reg = hfi1_pkt_base_sdma_integrity(dd);
-
-       if (HFI1_CAP_IS_KSET(STATIC_RATE_CTRL))
-               CLEAR_STATIC_RATE_CONTROL_SMASK(reg);
-       else
-               SET_STATIC_RATE_CONTROL_SMASK(reg);
 
-       write_sde_csr(sde, SD(CHECK_ENABLE), reg);
+       write_sde_csr(sde, SD(CHECK_ENABLE),
+                     hfi1_pkt_base_sdma_integrity(dd));
 }
 
 static void init_sdma_regs(
index edba22461a9c16dc86af705b2b86952d9fb85867..919a5474e6512a237fa0b6059f3f77f4a671103e 100644 (file)
@@ -49,7 +49,6 @@
 #include "hfi.h"
 #include "mad.h"
 #include "trace.h"
-#include "affinity.h"
 
 /*
  * Start of per-port congestion control structures and support code
@@ -623,27 +622,6 @@ static ssize_t show_tempsense(struct device *device,
        return ret;
 }
 
-static ssize_t show_sdma_affinity(struct device *device,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct hfi1_ibdev *dev =
-               container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
-       struct hfi1_devdata *dd = dd_from_dev(dev);
-
-       return hfi1_get_sdma_affinity(dd, buf);
-}
-
-static ssize_t store_sdma_affinity(struct device *device,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t count)
-{
-       struct hfi1_ibdev *dev =
-               container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
-       struct hfi1_devdata *dd = dd_from_dev(dev);
-
-       return hfi1_set_sdma_affinity(dd, buf, count);
-}
-
 /*
  * end of per-unit (or driver, in some cases, but replicated
  * per unit) functions
@@ -658,8 +636,6 @@ static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
 static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
 static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
 static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
-static DEVICE_ATTR(sdma_affinity, S_IWUSR | S_IRUGO, show_sdma_affinity,
-                  store_sdma_affinity);
 
 static struct device_attribute *hfi1_attributes[] = {
        &dev_attr_hw_rev,
@@ -670,7 +646,6 @@ static struct device_attribute *hfi1_attributes[] = {
        &dev_attr_boardversion,
        &dev_attr_tempsense,
        &dev_attr_chip_reset,
-       &dev_attr_sdma_affinity,
 };
 
 int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
index 11e02b22892281f5e5a2248a00f5f7ad4d1e9834..f77e59fb43fee7934fc15096b703cfb962f89f5a 100644 (file)
@@ -253,66 +253,6 @@ TRACE_EVENT(hfi1_mmu_invalidate,
                      )
            );
 
-#define SNOOP_PRN \
-       "slid %.4x dlid %.4x qpn 0x%.6x opcode 0x%.2x,%s " \
-       "svc lvl %d pkey 0x%.4x [header = %d bytes] [data = %d bytes]"
-
-TRACE_EVENT(snoop_capture,
-           TP_PROTO(struct hfi1_devdata *dd,
-                    int hdr_len,
-                    struct ib_header *hdr,
-                    int data_len,
-                    void *data),
-           TP_ARGS(dd, hdr_len, hdr, data_len, data),
-           TP_STRUCT__entry(
-                            DD_DEV_ENTRY(dd)
-                            __field(u16, slid)
-                            __field(u16, dlid)
-                            __field(u32, qpn)
-                            __field(u8, opcode)
-                            __field(u8, sl)
-                            __field(u16, pkey)
-                            __field(u32, hdr_len)
-                            __field(u32, data_len)
-                            __field(u8, lnh)
-                            __dynamic_array(u8, raw_hdr, hdr_len)
-                            __dynamic_array(u8, raw_pkt, data_len)
-                            ),
-           TP_fast_assign(
-               struct ib_other_headers *ohdr;
-
-               __entry->lnh = (u8)(be16_to_cpu(hdr->lrh[0]) & 3);
-               if (__entry->lnh == HFI1_LRH_BTH)
-               ohdr = &hdr->u.oth;
-               else
-               ohdr = &hdr->u.l.oth;
-               DD_DEV_ASSIGN(dd);
-               __entry->slid = be16_to_cpu(hdr->lrh[3]);
-               __entry->dlid = be16_to_cpu(hdr->lrh[1]);
-               __entry->qpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
-               __entry->opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff;
-               __entry->sl = (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
-               __entry->pkey = be32_to_cpu(ohdr->bth[0]) & 0xffff;
-               __entry->hdr_len = hdr_len;
-               __entry->data_len = data_len;
-               memcpy(__get_dynamic_array(raw_hdr), hdr, hdr_len);
-               memcpy(__get_dynamic_array(raw_pkt), data, data_len);
-               ),
-           TP_printk(
-               "[%s] " SNOOP_PRN,
-               __get_str(dev),
-               __entry->slid,
-               __entry->dlid,
-               __entry->qpn,
-               __entry->opcode,
-               show_ib_opcode(__entry->opcode),
-               __entry->sl,
-               __entry->pkey,
-               __entry->hdr_len,
-               __entry->data_len
-               )
-);
-
 #endif /* __HFI1_TRACE_RX_H */
 
 #undef TRACE_INCLUDE_PATH
index a761f804111eea026855bc3c2d033430f4e81807..77697d690f3eb12add14aed6a9fe19dafd498601 100644 (file)
@@ -1144,7 +1144,7 @@ static int pin_vector_pages(struct user_sdma_request *req,
        rb_node = hfi1_mmu_rb_extract(pq->handler,
                                      (unsigned long)iovec->iov.iov_base,
                                      iovec->iov.iov_len);
-       if (rb_node && !IS_ERR(rb_node))
+       if (rb_node)
                node = container_of(rb_node, struct sdma_mmu_node, rb);
        else
                rb_node = NULL;
index 5fc62336273132a80eebe1e8f3045758edd12d72..b9bf0759f10a54f37e242b8d07c54c56a063e859 100644 (file)
@@ -102,7 +102,10 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
        if (vlan_tag < 0x1000)
                vlan_tag |= (ah_attr->sl & 7) << 13;
        ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
-       ah->av.eth.gid_index = mlx4_ib_gid_index_to_real_index(ibdev, ah_attr->port_num, ah_attr->grh.sgid_index);
+       ret = mlx4_ib_gid_index_to_real_index(ibdev, ah_attr->port_num, ah_attr->grh.sgid_index);
+       if (ret < 0)
+               return ERR_PTR(ret);
+       ah->av.eth.gid_index = ret;
        ah->av.eth.vlan = cpu_to_be16(vlan_tag);
        ah->av.eth.hop_limit = ah_attr->grh.hop_limit;
        if (ah_attr->static_rate) {
index 1ea686b9e0f963cbfb49dc22fa4333f30922431e..6a0fec357daecdd1e049690af1495fc333b8c9bc 100644 (file)
@@ -253,11 +253,14 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev,
        if (context)
                if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof (__u32))) {
                        err = -EFAULT;
-                       goto err_dbmap;
+                       goto err_cq_free;
                }
 
        return &cq->ibcq;
 
+err_cq_free:
+       mlx4_cq_free(dev->dev, &cq->mcq);
+
 err_dbmap:
        if (context)
                mlx4_ib_db_unmap_user(to_mucontext(context), &cq->db);
index 79d017baf6f49dac160090d1e75ec75fd8b3cf2c..fcd04b881ec1924eb679827e18c0a2f8f6f3fd39 100644 (file)
@@ -932,8 +932,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
                if (err)
                        goto err_create;
        } else {
-               /* for now choose 64 bytes till we have a proper interface */
-               cqe_size = 64;
+               cqe_size = cache_line_size() == 128 ? 128 : 64;
                err = create_cq_kernel(dev, cq, entries, cqe_size, &cqb,
                                       &index, &inlen);
                if (err)
index 22174774dbb8c392709936b0eb225d3e6768d2c4..32b09f059c84a460b8e3bc5f80db2bb6fb892709 100644 (file)
@@ -1019,7 +1019,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
        resp.qp_tab_size = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp);
        if (mlx5_core_is_pf(dev->mdev) && MLX5_CAP_GEN(dev->mdev, bf))
                resp.bf_reg_size = 1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size);
-       resp.cache_line_size = L1_CACHE_BYTES;
+       resp.cache_line_size = cache_line_size();
        resp.max_sq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq);
        resp.max_rq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq);
        resp.max_send_wqebb = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz);
@@ -2311,14 +2311,14 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context,
 {
        struct mlx5_ib_dev *ibdev = (struct mlx5_ib_dev *)context;
        struct ib_event ibev;
-
+       bool fatal = false;
        u8 port = 0;
 
        switch (event) {
        case MLX5_DEV_EVENT_SYS_ERROR:
-               ibdev->ib_active = false;
                ibev.event = IB_EVENT_DEVICE_FATAL;
                mlx5_ib_handle_internal_error(ibdev);
+               fatal = true;
                break;
 
        case MLX5_DEV_EVENT_PORT_UP:
@@ -2370,6 +2370,9 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context,
 
        if (ibdev->ib_active)
                ib_dispatch_event(&ibev);
+
+       if (fatal)
+               ibdev->ib_active = false;
 }
 
 static void get_ext_port_caps(struct mlx5_ib_dev *dev)
@@ -3115,7 +3118,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
        }
        err = init_node_data(dev);
        if (err)
-               goto err_dealloc;
+               goto err_free_port;
 
        mutex_init(&dev->flow_db.lock);
        mutex_init(&dev->cap_mask_mutex);
@@ -3125,7 +3128,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
        if (ll == IB_LINK_LAYER_ETHERNET) {
                err = mlx5_enable_roce(dev);
                if (err)
-                       goto err_dealloc;
+                       goto err_free_port;
        }
 
        err = create_dev_resources(&dev->devr);
index dcdcd195fe53a4dd003b0d22426d146bb81c0380..7d689903c87cfea2a84755f81362095c97167c8d 100644 (file)
@@ -626,6 +626,8 @@ struct mlx5_ib_dev {
        struct mlx5_ib_resources        devr;
        struct mlx5_mr_cache            cache;
        struct timer_list               delay_timer;
+       /* Prevents soft lock on massive reg MRs */
+       struct mutex                    slow_path_mutex;
        int                             fill_delay;
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
        struct ib_odp_caps      odp_caps;
index d4ad672b905bf0068b59b2ebffe8de8a85f035e1..4e9012463c37de6381cddde1c527e4c2ff6e84ae 100644 (file)
@@ -610,6 +610,7 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev)
        int err;
        int i;
 
+       mutex_init(&dev->slow_path_mutex);
        cache->wq = alloc_ordered_workqueue("mkey_cache", WQ_MEM_RECLAIM);
        if (!cache->wq) {
                mlx5_ib_warn(dev, "failed to create work queue\n");
@@ -1182,9 +1183,12 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
                goto error;
        }
 
-       if (!mr)
+       if (!mr) {
+               mutex_lock(&dev->slow_path_mutex);
                mr = reg_create(NULL, pd, virt_addr, length, umem, ncont,
                                page_shift, access_flags);
+               mutex_unlock(&dev->slow_path_mutex);
+       }
 
        if (IS_ERR(mr)) {
                err = PTR_ERR(mr);
index 41f4c2afbcdd6264a05c38d9c0cd2ce7d807bccc..d1e921816bfee3596c961e6671d87a84a3caa0ab 100644 (file)
@@ -52,7 +52,6 @@ enum {
 
 enum {
        MLX5_IB_SQ_STRIDE       = 6,
-       MLX5_IB_CACHE_LINE_SIZE = 64,
 };
 
 static const u32 mlx5_ib_opcode[] = {
@@ -2052,8 +2051,8 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
 
                mlx5_ib_dbg(dev, "ib qpnum 0x%x, mlx qpn 0x%x, rcqn 0x%x, scqn 0x%x\n",
                            qp->ibqp.qp_num, qp->trans_qp.base.mqp.qpn,
-                           to_mcq(init_attr->recv_cq)->mcq.cqn,
-                           to_mcq(init_attr->send_cq)->mcq.cqn);
+                           init_attr->recv_cq ? to_mcq(init_attr->recv_cq)->mcq.cqn : -1,
+                           init_attr->send_cq ? to_mcq(init_attr->send_cq)->mcq.cqn : -1);
 
                qp->trans_qp.xrcdn = xrcdn;
 
@@ -4815,6 +4814,14 @@ struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
                                 udata->inlen))
                return ERR_PTR(-EOPNOTSUPP);
 
+       if (init_attr->log_ind_tbl_size >
+           MLX5_CAP_GEN(dev->mdev, log_max_rqt_size)) {
+               mlx5_ib_dbg(dev, "log_ind_tbl_size = %d is bigger than supported = %d\n",
+                           init_attr->log_ind_tbl_size,
+                           MLX5_CAP_GEN(dev->mdev, log_max_rqt_size));
+               return ERR_PTR(-EINVAL);
+       }
+
        min_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
        if (udata->outlen && udata->outlen < min_resp_len)
                return ERR_PTR(-EINVAL);
index 6c00d04b8b2852369f4f43d78c39c68898ff4640..c6fe89d79248fa28d05282440ede6f67cd35e75c 100644 (file)
@@ -472,7 +472,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
                goto out;
        }
 
-       ret = get_user_pages(uaddr & PAGE_MASK, 1, 1, 0, pages, NULL);
+       ret = get_user_pages(uaddr & PAGE_MASK, 1, FOLL_WRITE, pages, NULL);
        if (ret < 0)
                goto out;
 
index 7c06d85568d445dc88a7b00471199cfa90dc5a24..6c9f3923e8382cdc25e913283f6fe6e539fbcaf5 100644 (file)
@@ -2,6 +2,7 @@ config INFINIBAND_QEDR
        tristate "QLogic RoCE driver"
        depends on 64BIT && QEDE
        select QED_LL2
+       select QED_RDMA
        ---help---
          This driver provides low-level InfiniBand over Ethernet
          support for QLogic QED host channel adapters (HCAs).
index 2d2b94fd3633bff1ddbed16d077ee436bbe0ae58..75f08624ac052abed2347cb462990c0545c8d828 100644 (file)
@@ -67,7 +67,8 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages,
 
        for (got = 0; got < num_pages; got += ret) {
                ret = get_user_pages(start_page + got * PAGE_SIZE,
-                                    num_pages - got, 1, 1,
+                                    num_pages - got,
+                                    FOLL_WRITE | FOLL_FORCE,
                                     p + got, NULL);
                if (ret < 0)
                        goto bail_release;
index a0b6ebee4d8a047e2fdffb8bbd831e5c36107fec..1ccee6ea5bc3092f196689c4481b21d9f27b796c 100644 (file)
@@ -111,6 +111,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
        int i;
        int flags;
        dma_addr_t pa;
+       unsigned int gup_flags;
 
        if (!can_do_mlock())
                return -EPERM;
@@ -135,6 +136,8 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
 
        flags = IOMMU_READ | IOMMU_CACHE;
        flags |= (writable) ? IOMMU_WRITE : 0;
+       gup_flags = FOLL_WRITE;
+       gup_flags |= (writable) ? 0 : FOLL_FORCE;
        cur_base = addr & PAGE_MASK;
        ret = 0;
 
@@ -142,7 +145,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
                ret = get_user_pages(cur_base,
                                        min_t(unsigned long, npages,
                                        PAGE_SIZE / sizeof(struct page *)),
-                                       1, !writable, page_list, NULL);
+                                       gup_flags, page_list, NULL);
 
                if (ret < 0)
                        goto out;
index 01f71caa3ac4f95994e20b72fedd91cb09a3fb9e..f2cefb0d918083516e3bd2319bcbc318fa852ef2 100644 (file)
@@ -90,9 +90,6 @@ static u64 rvt_dma_map_page(struct ib_device *dev, struct page *page,
        if (WARN_ON(!valid_dma_direction(direction)))
                return BAD_DMA_ADDRESS;
 
-       if (offset + size > PAGE_SIZE)
-               return BAD_DMA_ADDRESS;
-
        addr = (u64)page_address(page);
        if (addr)
                addr += offset;
index b8258e4f0aeaf656cfa8f98f6f80bf3761b6bd2b..ffff5a54cb340d9d95d6bef83ce78ff456011d46 100644 (file)
@@ -243,10 +243,8 @@ static struct socket *rxe_setup_udp_tunnel(struct net *net, __be16 port,
 {
        int err;
        struct socket *sock;
-       struct udp_port_cfg udp_cfg;
-       struct udp_tunnel_sock_cfg tnl_cfg;
-
-       memset(&udp_cfg, 0, sizeof(udp_cfg));
+       struct udp_port_cfg udp_cfg = {0};
+       struct udp_tunnel_sock_cfg tnl_cfg = {0};
 
        if (ipv6) {
                udp_cfg.family = AF_INET6;
@@ -264,10 +262,8 @@ static struct socket *rxe_setup_udp_tunnel(struct net *net, __be16 port,
                return ERR_PTR(err);
        }
 
-       tnl_cfg.sk_user_data = NULL;
        tnl_cfg.encap_type = 1;
        tnl_cfg.encap_rcv = rxe_udp_encap_recv;
-       tnl_cfg.encap_destroy = NULL;
 
        /* Setup UDP tunnel */
        setup_udp_tunnel_sock(net, sock, &tnl_cfg);
index b8036cfbce04041d77a3679979ed5def0d9a0b46..c3e60e4bde6e2a3ba5e0953b531a42f65927b717 100644 (file)
@@ -522,6 +522,7 @@ static void rxe_qp_reset(struct rxe_qp *qp)
        if (qp->sq.queue) {
                __rxe_do_task(&qp->comp.task);
                __rxe_do_task(&qp->req.task);
+               rxe_queue_reset(qp->sq.queue);
        }
 
        /* cleanup attributes */
@@ -573,6 +574,7 @@ void rxe_qp_error(struct rxe_qp *qp)
 {
        qp->req.state = QP_STATE_ERROR;
        qp->resp.state = QP_STATE_ERROR;
+       qp->attr.qp_state = IB_QPS_ERR;
 
        /* drain work and packet queues */
        rxe_run_task(&qp->resp.task, 1);
index 08274254eb887531068d8239dd13c95a16ef190c..d14bf496d62d3af7581bb307fa1350989a90f042 100644 (file)
@@ -84,6 +84,15 @@ err1:
        return -EINVAL;
 }
 
+inline void rxe_queue_reset(struct rxe_queue *q)
+{
+       /* queue is comprised from header and the memory
+        * of the actual queue. See "struct rxe_queue_buf" in rxe_queue.h
+        * reset only the queue itself and not the management header
+        */
+       memset(q->buf->data, 0, q->buf_size - sizeof(struct rxe_queue_buf));
+}
+
 struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
                                 int *num_elem,
                                 unsigned int elem_size)
index 239fd609c31ef51b47d306420a54a26d3ddeb185..8c8641c87817f3fcb6024e58ae31311179d4d060 100644 (file)
@@ -84,6 +84,8 @@ int do_mmap_info(struct rxe_dev *rxe,
                 size_t buf_size,
                 struct rxe_mmap_info **ip_p);
 
+void rxe_queue_reset(struct rxe_queue *q);
+
 struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
                                 int *num_elem,
                                 unsigned int elem_size);
index 832846b73ea0252f8b8eda61b0af58d92ab92afc..22bd9630dcd924315012019ff0a39242d7476a59 100644 (file)
@@ -696,7 +696,8 @@ next_wqe:
                                                       qp->req.wqe_index);
                        wqe->state = wqe_state_done;
                        wqe->status = IB_WC_SUCCESS;
-                       goto complete;
+                       __rxe_do_task(&qp->comp.task);
+                       return 0;
                }
                payload = mtu;
        }
@@ -745,13 +746,17 @@ err:
        wqe->status = IB_WC_LOC_PROT_ERR;
        wqe->state = wqe_state_error;
 
-complete:
-       if (qp_type(qp) != IB_QPT_RC) {
-               while (rxe_completer(qp) == 0)
-                       ;
-       }
-
-       return 0;
+       /*
+        * IBA Spec. Section 10.7.3.1 SIGNALED COMPLETIONS
+        * ---------8<---------8<-------------
+        * ...Note that if a completion error occurs, a Work Completion
+        * will always be generated, even if the signaling
+        * indicator requests an Unsignaled Completion.
+        * ---------8<---------8<-------------
+        */
+       wqe->wr.send_flags |= IB_SEND_SIGNALED;
+       __rxe_do_task(&qp->comp.task);
+       return -EAGAIN;
 
 exit:
        return -EAGAIN;
index 7b8d2d9e22633f140b601d0056438bd7d9ca3e68..da12717a3eb794f100438988c564eb56004ef0d7 100644 (file)
@@ -63,6 +63,8 @@ enum ipoib_flush_level {
 
 enum {
        IPOIB_ENCAP_LEN           = 4,
+       IPOIB_PSEUDO_LEN          = 20,
+       IPOIB_HARD_LEN            = IPOIB_ENCAP_LEN + IPOIB_PSEUDO_LEN,
 
        IPOIB_UD_HEAD_SIZE        = IB_GRH_BYTES + IPOIB_ENCAP_LEN,
        IPOIB_UD_RX_SG            = 2, /* max buffer needed for 4K mtu */
@@ -134,15 +136,21 @@ struct ipoib_header {
        u16     reserved;
 };
 
-struct ipoib_cb {
-       struct qdisc_skb_cb     qdisc_cb;
-       u8                      hwaddr[INFINIBAND_ALEN];
+struct ipoib_pseudo_header {
+       u8      hwaddr[INFINIBAND_ALEN];
 };
 
-static inline struct ipoib_cb *ipoib_skb_cb(const struct sk_buff *skb)
+static inline void skb_add_pseudo_hdr(struct sk_buff *skb)
 {
-       BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct ipoib_cb));
-       return (struct ipoib_cb *)skb->cb;
+       char *data = skb_push(skb, IPOIB_PSEUDO_LEN);
+
+       /*
+        * only the ipoib header is present now, make room for a dummy
+        * pseudo header and set skb field accordingly
+        */
+       memset(data, 0, IPOIB_PSEUDO_LEN);
+       skb_reset_mac_header(skb);
+       skb_pull(skb, IPOIB_HARD_LEN);
 }
 
 /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
index 4ad297d3de897789141c87847d26d6fdf91a062e..339a1eecdfe3083e2b15d09473a1053113b7acaa 100644 (file)
@@ -63,6 +63,8 @@ MODULE_PARM_DESC(cm_data_debug_level,
 #define IPOIB_CM_RX_DELAY       (3 * 256 * HZ)
 #define IPOIB_CM_RX_UPDATE_MASK (0x3)
 
+#define IPOIB_CM_RX_RESERVE     (ALIGN(IPOIB_HARD_LEN, 16) - IPOIB_ENCAP_LEN)
+
 static struct ib_qp_attr ipoib_cm_err_attr = {
        .qp_state = IB_QPS_ERR
 };
@@ -146,15 +148,15 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev,
        struct sk_buff *skb;
        int i;
 
-       skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12);
+       skb = dev_alloc_skb(ALIGN(IPOIB_CM_HEAD_SIZE + IPOIB_PSEUDO_LEN, 16));
        if (unlikely(!skb))
                return NULL;
 
        /*
-        * IPoIB adds a 4 byte header. So we need 12 more bytes to align the
+        * IPoIB adds a IPOIB_ENCAP_LEN byte header, this will align the
         * IP header to a multiple of 16.
         */
-       skb_reserve(skb, 12);
+       skb_reserve(skb, IPOIB_CM_RX_RESERVE);
 
        mapping[0] = ib_dma_map_single(priv->ca, skb->data, IPOIB_CM_HEAD_SIZE,
                                       DMA_FROM_DEVICE);
@@ -624,9 +626,9 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        if (wc->byte_len < IPOIB_CM_COPYBREAK) {
                int dlen = wc->byte_len;
 
-               small_skb = dev_alloc_skb(dlen + 12);
+               small_skb = dev_alloc_skb(dlen + IPOIB_CM_RX_RESERVE);
                if (small_skb) {
-                       skb_reserve(small_skb, 12);
+                       skb_reserve(small_skb, IPOIB_CM_RX_RESERVE);
                        ib_dma_sync_single_for_cpu(priv->ca, rx_ring[wr_id].mapping[0],
                                                   dlen, DMA_FROM_DEVICE);
                        skb_copy_from_linear_data(skb, small_skb->data, dlen);
@@ -663,8 +665,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 
 copied:
        skb->protocol = ((struct ipoib_header *) skb->data)->proto;
-       skb_reset_mac_header(skb);
-       skb_pull(skb, IPOIB_ENCAP_LEN);
+       skb_add_pseudo_hdr(skb);
 
        ++dev->stats.rx_packets;
        dev->stats.rx_bytes += skb->len;
index be11d5d5b8c1d9ca84ab884bac32000e018c4c60..830fecb6934c8edf60a4c1d138cd4815be4b1314 100644 (file)
@@ -128,16 +128,15 @@ static struct sk_buff *ipoib_alloc_rx_skb(struct net_device *dev, int id)
 
        buf_size = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu);
 
-       skb = dev_alloc_skb(buf_size + IPOIB_ENCAP_LEN);
+       skb = dev_alloc_skb(buf_size + IPOIB_HARD_LEN);
        if (unlikely(!skb))
                return NULL;
 
        /*
-        * IB will leave a 40 byte gap for a GRH and IPoIB adds a 4 byte
-        * header.  So we need 4 more bytes to get to 48 and align the
-        * IP header to a multiple of 16.
+        * the IP header will be at IPOIP_HARD_LEN + IB_GRH_BYTES, that is
+        * 64 bytes aligned
         */
-       skb_reserve(skb, 4);
+       skb_reserve(skb, sizeof(struct ipoib_pseudo_header));
 
        mapping = priv->rx_ring[id].mapping;
        mapping[0] = ib_dma_map_single(priv->ca, skb->data, buf_size,
@@ -253,8 +252,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        skb_pull(skb, IB_GRH_BYTES);
 
        skb->protocol = ((struct ipoib_header *) skb->data)->proto;
-       skb_reset_mac_header(skb);
-       skb_pull(skb, IPOIB_ENCAP_LEN);
+       skb_add_pseudo_hdr(skb);
 
        ++dev->stats.rx_packets;
        dev->stats.rx_bytes += skb->len;
index 5636fc3da6b867aaabe5c1ff7f197d3f0077df76..b58d9dca5c934eb69c9f62b623216d7856999105 100644 (file)
@@ -925,9 +925,12 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
                                ipoib_neigh_free(neigh);
                                goto err_drop;
                        }
-                       if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)
+                       if (skb_queue_len(&neigh->queue) <
+                           IPOIB_MAX_PATH_REC_QUEUE) {
+                               /* put pseudoheader back on for next time */
+                               skb_push(skb, IPOIB_PSEUDO_LEN);
                                __skb_queue_tail(&neigh->queue, skb);
-                       else {
+                       else {
                                ipoib_warn(priv, "queue length limit %d. Packet drop.\n",
                                           skb_queue_len(&neigh->queue));
                                goto err_drop;
@@ -964,7 +967,7 @@ err_drop:
 }
 
 static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
-                            struct ipoib_cb *cb)
+                            struct ipoib_pseudo_header *phdr)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_path *path;
@@ -972,16 +975,18 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       path = __path_find(dev, cb->hwaddr + 4);
+       path = __path_find(dev, phdr->hwaddr + 4);
        if (!path || !path->valid) {
                int new_path = 0;
 
                if (!path) {
-                       path = path_rec_create(dev, cb->hwaddr + 4);
+                       path = path_rec_create(dev, phdr->hwaddr + 4);
                        new_path = 1;
                }
                if (path) {
                        if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+                               /* put pseudoheader back on for next time */
+                               skb_push(skb, IPOIB_PSEUDO_LEN);
                                __skb_queue_tail(&path->queue, skb);
                        } else {
                                ++dev->stats.tx_dropped;
@@ -1009,10 +1014,12 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
                          be16_to_cpu(path->pathrec.dlid));
 
                spin_unlock_irqrestore(&priv->lock, flags);
-               ipoib_send(dev, skb, path->ah, IPOIB_QPN(cb->hwaddr));
+               ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr));
                return;
        } else if ((path->query || !path_rec_start(dev, path)) &&
                   skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+               /* put pseudoheader back on for next time */
+               skb_push(skb, IPOIB_PSEUDO_LEN);
                __skb_queue_tail(&path->queue, skb);
        } else {
                ++dev->stats.tx_dropped;
@@ -1026,13 +1033,15 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_neigh *neigh;
-       struct ipoib_cb *cb = ipoib_skb_cb(skb);
+       struct ipoib_pseudo_header *phdr;
        struct ipoib_header *header;
        unsigned long flags;
 
+       phdr = (struct ipoib_pseudo_header *) skb->data;
+       skb_pull(skb, sizeof(*phdr));
        header = (struct ipoib_header *) skb->data;
 
-       if (unlikely(cb->hwaddr[4] == 0xff)) {
+       if (unlikely(phdr->hwaddr[4] == 0xff)) {
                /* multicast, arrange "if" according to probability */
                if ((header->proto != htons(ETH_P_IP)) &&
                    (header->proto != htons(ETH_P_IPV6)) &&
@@ -1045,13 +1054,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        return NETDEV_TX_OK;
                }
                /* Add in the P_Key for multicast*/
-               cb->hwaddr[8] = (priv->pkey >> 8) & 0xff;
-               cb->hwaddr[9] = priv->pkey & 0xff;
+               phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
+               phdr->hwaddr[9] = priv->pkey & 0xff;
 
-               neigh = ipoib_neigh_get(dev, cb->hwaddr);
+               neigh = ipoib_neigh_get(dev, phdr->hwaddr);
                if (likely(neigh))
                        goto send_using_neigh;
-               ipoib_mcast_send(dev, cb->hwaddr, skb);
+               ipoib_mcast_send(dev, phdr->hwaddr, skb);
                return NETDEV_TX_OK;
        }
 
@@ -1060,16 +1069,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
        case htons(ETH_P_IP):
        case htons(ETH_P_IPV6):
        case htons(ETH_P_TIPC):
-               neigh = ipoib_neigh_get(dev, cb->hwaddr);
+               neigh = ipoib_neigh_get(dev, phdr->hwaddr);
                if (unlikely(!neigh)) {
-                       neigh_add_path(skb, cb->hwaddr, dev);
+                       neigh_add_path(skb, phdr->hwaddr, dev);
                        return NETDEV_TX_OK;
                }
                break;
        case htons(ETH_P_ARP):
        case htons(ETH_P_RARP):
                /* for unicast ARP and RARP should always perform path find */
-               unicast_arp_send(skb, dev, cb);
+               unicast_arp_send(skb, dev, phdr);
                return NETDEV_TX_OK;
        default:
                /* ethertype not supported by IPoIB */
@@ -1086,11 +1095,13 @@ send_using_neigh:
                        goto unref;
                }
        } else if (neigh->ah) {
-               ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(cb->hwaddr));
+               ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(phdr->hwaddr));
                goto unref;
        }
 
        if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+               /* put pseudoheader back on for next time */
+               skb_push(skb, sizeof(*phdr));
                spin_lock_irqsave(&priv->lock, flags);
                __skb_queue_tail(&neigh->queue, skb);
                spin_unlock_irqrestore(&priv->lock, flags);
@@ -1122,8 +1133,8 @@ static int ipoib_hard_header(struct sk_buff *skb,
                             unsigned short type,
                             const void *daddr, const void *saddr, unsigned len)
 {
+       struct ipoib_pseudo_header *phdr;
        struct ipoib_header *header;
-       struct ipoib_cb *cb = ipoib_skb_cb(skb);
 
        header = (struct ipoib_header *) skb_push(skb, sizeof *header);
 
@@ -1132,12 +1143,13 @@ static int ipoib_hard_header(struct sk_buff *skb,
 
        /*
         * we don't rely on dst_entry structure,  always stuff the
-        * destination address into skb->cb so we can figure out where
+        * destination address into skb hard header so we can figure out where
         * to send the packet later.
         */
-       memcpy(cb->hwaddr, daddr, INFINIBAND_ALEN);
+       phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr));
+       memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
 
-       return sizeof *header;
+       return IPOIB_HARD_LEN;
 }
 
 static void ipoib_set_mcast_list(struct net_device *dev)
@@ -1759,7 +1771,7 @@ void ipoib_setup(struct net_device *dev)
 
        dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
 
-       dev->hard_header_len     = IPOIB_ENCAP_LEN;
+       dev->hard_header_len     = IPOIB_HARD_LEN;
        dev->addr_len            = INFINIBAND_ALEN;
        dev->type                = ARPHRD_INFINIBAND;
        dev->tx_queue_len        = ipoib_sendq_size * 2;
index d3394b6add24a0303dd51710d72f86087a36c7fe..1909dd252c9406ba4700e96d5730a67c51ba1a91 100644 (file)
@@ -796,9 +796,11 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)
                        __ipoib_mcast_add(dev, mcast);
                        list_add_tail(&mcast->list, &priv->multicast_list);
                }
-               if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
+               if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) {
+                       /* put pseudoheader back on for next time */
+                       skb_push(skb, sizeof(struct ipoib_pseudo_header));
                        skb_queue_tail(&mcast->pkt_queue, skb);
-               else {
+               else {
                        ++dev->stats.tx_dropped;
                        dev_kfree_skb_any(skb);
                }
index 9829363345372add0e3a5fd6812ff49a6d527aba..07ec465f109587e48b946c9513f7b1fbc98a5619 100644 (file)
@@ -37,6 +37,8 @@ static void arizona_haptics_work(struct work_struct *work)
                                                       struct arizona_haptics,
                                                       work);
        struct arizona *arizona = haptics->arizona;
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(arizona->dapm);
        int ret;
 
        if (!haptics->arizona->dapm) {
@@ -66,7 +68,7 @@ static void arizona_haptics_work(struct work_struct *work)
                        return;
                }
 
-               ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
+               ret = snd_soc_component_enable_pin(component, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
                                ret);
@@ -81,7 +83,7 @@ static void arizona_haptics_work(struct work_struct *work)
                }
        } else {
                /* This disable sequence will be a noop if already enabled */
-               ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
+               ret = snd_soc_component_disable_pin(component, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
                                ret);
@@ -140,11 +142,14 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
 static void arizona_haptics_close(struct input_dev *input)
 {
        struct arizona_haptics *haptics = input_get_drvdata(input);
+       struct snd_soc_component *component;
 
        cancel_work_sync(&haptics->work);
 
-       if (haptics->arizona->dapm)
-               snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
+       if (haptics->arizona->dapm) {
+               component = snd_soc_dapm_to_component(haptics->arizona->dapm);
+               snd_soc_component_disable_pin(component, "HAPTICS");
+       }
 }
 
 static int arizona_haptics_probe(struct platform_device *pdev)
index 54eceb30ede5090e67415a7e70ae5f43d7dd9b3f..a7d39689bbfb6fc7df84f6a01a8b78bdc0cc6a99 100644 (file)
@@ -43,7 +43,7 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties)
 
        if (set_properties) {
                psmouse->vendor = "FocalTech";
-               psmouse->name = "FocalTech Touchpad";
+               psmouse->name = "Touchpad";
        }
 
        return 0;
@@ -146,8 +146,8 @@ static void focaltech_report_state(struct psmouse *psmouse)
        }
        input_mt_report_pointer_emulation(dev, true);
 
-       input_report_key(psmouse->dev, BTN_LEFT, state->pressed);
-       input_sync(psmouse->dev);
+       input_report_key(dev, BTN_LEFT, state->pressed);
+       input_sync(dev);
 }
 
 static void focaltech_process_touch_packet(struct psmouse *psmouse,
index fb4b185dea963e8a93fba4688a8e7ab5621c2b99..bee2674249722fd4117a7d7de95d222749c6b86a 100644 (file)
@@ -1115,10 +1115,6 @@ static int psmouse_extensions(struct psmouse *psmouse,
                if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2,
                                         &max_proto, set_properties, true))
                        return PSMOUSE_TOUCHKIT_PS2;
-
-               if (psmouse_try_protocol(psmouse, PSMOUSE_BYD,
-                                        &max_proto, set_properties, true))
-                       return PSMOUSE_BYD;
        }
 
        /*
index f4bfb4b2d50a356336fdab08124f52085a82f24f..073246c7d1634eef411c1bf07d7f72ab47cad369 100644 (file)
@@ -877,6 +877,13 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
                },
        },
+       {
+               /* Schenker XMG C504 - Elantech touchpad */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "XMG"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "C504"),
+               },
+       },
        { }
 };
 
index 15c01c3cd540b6b0416002ca39c8a72951b3cc75..e6f9b2d745ca0eefbe02cb5e9c2680dcff60af46 100644 (file)
@@ -2636,17 +2636,26 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
        /* And we're up. Go go go! */
        of_iommu_set_ops(dev->of_node, &arm_smmu_ops);
 #ifdef CONFIG_PCI
-       pci_request_acs();
-       ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
-       if (ret)
-               return ret;
+       if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
+               pci_request_acs();
+               ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
+               if (ret)
+                       return ret;
+       }
 #endif
 #ifdef CONFIG_ARM_AMBA
-       ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
-       if (ret)
-               return ret;
+       if (amba_bustype.iommu_ops != &arm_smmu_ops) {
+               ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+               if (ret)
+                       return ret;
+       }
 #endif
-       return bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+       if (platform_bus_type.iommu_ops != &arm_smmu_ops) {
+               ret = bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+               if (ret)
+                       return ret;
+       }
+       return 0;
 }
 
 static int arm_smmu_device_remove(struct platform_device *pdev)
index c841eb7a1a7417af301e6c51a9ba464d05b1472a..8f7281444551dfc8a7b1a1bbfdb66a81f28e01ca 100644 (file)
@@ -324,8 +324,10 @@ struct arm_smmu_master_cfg {
 #define INVALID_SMENDX                 -1
 #define __fwspec_cfg(fw) ((struct arm_smmu_master_cfg *)fw->iommu_priv)
 #define fwspec_smmu(fw)  (__fwspec_cfg(fw)->smmu)
+#define fwspec_smendx(fw, i) \
+       (i >= fw->num_ids ? INVALID_SMENDX : __fwspec_cfg(fw)->smendx[i])
 #define for_each_cfg_sme(fw, i, idx) \
-       for (i = 0; idx = __fwspec_cfg(fw)->smendx[i], i < fw->num_ids; ++i)
+       for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
 
 struct arm_smmu_device {
        struct device                   *dev;
@@ -1228,6 +1230,16 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
                return -ENXIO;
        }
 
+       /*
+        * FIXME: The arch/arm DMA API code tries to attach devices to its own
+        * domains between of_xlate() and add_device() - we have no way to cope
+        * with that, so until ARM gets converted to rely on groups and default
+        * domains, just say no (but more politely than by dereferencing NULL).
+        * This should be at least a WARN_ON once that's sorted.
+        */
+       if (!fwspec->iommu_priv)
+               return -ENODEV;
+
        smmu = fwspec_smmu(fwspec);
        /* Ensure that the domain is finalised */
        ret = arm_smmu_init_domain_context(domain, smmu);
@@ -1390,7 +1402,7 @@ static int arm_smmu_add_device(struct device *dev)
                fwspec = dev->iommu_fwspec;
                if (ret)
                        goto out_free;
-       } else if (fwspec) {
+       } else if (fwspec && fwspec->ops == &arm_smmu_ops) {
                smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode));
        } else {
                return -ENODEV;
index 58470f5ced04a9547428ec538dbdec3c58f9a1f2..8c53748a769d447fac83622725c305a3ee6bc92f 100644 (file)
@@ -338,7 +338,9 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
        struct pci_dev *pdev = to_pci_dev(data);
        struct dmar_pci_notify_info *info;
 
-       /* Only care about add/remove events for physical functions */
+       /* Only care about add/remove events for physical functions.
+        * For VFs we actually do the lookup based on the corresponding
+        * PF in device_to_iommu() anyway. */
        if (pdev->is_virtfn)
                return NOTIFY_DONE;
        if (action != BUS_NOTIFY_ADD_DEVICE &&
index a4407eabf0e64fbacba5573bc3eb91204c97a19c..d8376c2d18b3bf7491cb80473053b1a34f6cd54f 100644 (file)
@@ -892,7 +892,13 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
                return NULL;
 
        if (dev_is_pci(dev)) {
+               struct pci_dev *pf_pdev;
+
                pdev = to_pci_dev(dev);
+               /* VFs aren't listed in scope tables; we need to look up
+                * the PF instead to find the IOMMU. */
+               pf_pdev = pci_physfn(pdev);
+               dev = &pf_pdev->dev;
                segment = pci_domain_nr(pdev->bus);
        } else if (has_acpi_companion(dev))
                dev = &ACPI_COMPANION(dev)->dev;
@@ -905,6 +911,13 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
                for_each_active_dev_scope(drhd->devices,
                                          drhd->devices_cnt, i, tmp) {
                        if (tmp == dev) {
+                               /* For a VF use its original BDF# not that of the PF
+                                * which we used for the IOMMU lookup. Strictly speaking
+                                * we could do this for all PCI devices; we only need to
+                                * get the BDF# from the scope table for ACPI matches. */
+                               if (pdev->is_virtfn)
+                                       goto got_pdev;
+
                                *bus = drhd->devices[i].bus;
                                *devfn = drhd->devices[i].devfn;
                                goto out;
@@ -1711,6 +1724,7 @@ static void disable_dmar_iommu(struct intel_iommu *iommu)
        if (!iommu->domains || !iommu->domain_ids)
                return;
 
+again:
        spin_lock_irqsave(&device_domain_lock, flags);
        list_for_each_entry_safe(info, tmp, &device_domain_list, global) {
                struct dmar_domain *domain;
@@ -1723,10 +1737,19 @@ static void disable_dmar_iommu(struct intel_iommu *iommu)
 
                domain = info->domain;
 
-               dmar_remove_one_dev_info(domain, info->dev);
+               __dmar_remove_one_dev_info(info);
 
-               if (!domain_type_is_vm_or_si(domain))
+               if (!domain_type_is_vm_or_si(domain)) {
+                       /*
+                        * The domain_exit() function  can't be called under
+                        * device_domain_lock, as it takes this lock itself.
+                        * So release the lock here and re-run the loop
+                        * afterwards.
+                        */
+                       spin_unlock_irqrestore(&device_domain_lock, flags);
                        domain_exit(domain);
+                       goto again;
+               }
        }
        spin_unlock_irqrestore(&device_domain_lock, flags);
 
index 8ebb3530afa7574810f849e7a333c19473740304..cb72e0011310d1fbd04cb1560a861c8e5ec2fd55 100644 (file)
@@ -39,10 +39,18 @@ int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu)
        struct page *pages;
        int order;
 
-       order = ecap_pss(iommu->ecap) + 7 - PAGE_SHIFT;
-       if (order < 0)
-               order = 0;
-
+       /* Start at 2 because it's defined as 2^(1+PSS) */
+       iommu->pasid_max = 2 << ecap_pss(iommu->ecap);
+
+       /* Eventually I'm promised we will get a multi-level PASID table
+        * and it won't have to be physically contiguous. Until then,
+        * limit the size because 8MiB contiguous allocations can be hard
+        * to come by. The limit of 0x20000, which is 1MiB for each of
+        * the PASID and PASID-state tables, is somewhat arbitrary. */
+       if (iommu->pasid_max > 0x20000)
+               iommu->pasid_max = 0x20000;
+
+       order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max);
        pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
        if (!pages) {
                pr_warn("IOMMU: %s: Failed to allocate PASID table\n",
@@ -53,6 +61,8 @@ int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu)
        pr_info("%s: Allocated order %d PASID table.\n", iommu->name, order);
 
        if (ecap_dis(iommu->ecap)) {
+               /* Just making it explicit... */
+               BUILD_BUG_ON(sizeof(struct pasid_entry) != sizeof(struct pasid_state_entry));
                pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
                if (pages)
                        iommu->pasid_state_table = page_address(pages);
@@ -68,11 +78,7 @@ int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu)
 
 int intel_svm_free_pasid_tables(struct intel_iommu *iommu)
 {
-       int order;
-
-       order = ecap_pss(iommu->ecap) + 7 - PAGE_SHIFT;
-       if (order < 0)
-               order = 0;
+       int order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max);
 
        if (iommu->pasid_table) {
                free_pages((unsigned long)iommu->pasid_table, order);
@@ -371,8 +377,8 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
                }
                svm->iommu = iommu;
 
-               if (pasid_max > 2 << ecap_pss(iommu->ecap))
-                       pasid_max = 2 << ecap_pss(iommu->ecap);
+               if (pasid_max > iommu->pasid_max)
+                       pasid_max = iommu->pasid_max;
 
                /* Do not use PASID 0 in caching mode (virtualised IOMMU) */
                ret = idr_alloc(&iommu->pasid_idr, svm,
index c0e7b624ce5475aed0022d3b6f79a043110740ff..12102448fdddf1371f5d561c81e04a55091e8b07 100644 (file)
@@ -178,7 +178,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
                       idev->id_vendor, idev->id_device);
 }
 
-ipack_device_attr(id_format, "0x%hhu\n");
+ipack_device_attr(id_format, "0x%hhx\n");
 
 static DEVICE_ATTR_RO(id);
 static DEVICE_ATTR_RO(id_device);
index 82b0b5daf3f5b2af6a91c18923271dc7647a7cef..bc0af3307bbfd6612d2ae18d37a15c8d87a6ea39 100644 (file)
@@ -158,8 +158,8 @@ config PIC32_EVIC
        select IRQ_DOMAIN
 
 config JCORE_AIC
-       bool "J-Core integrated AIC"
-       depends on OF && (SUPERH || COMPILE_TEST)
+       bool "J-Core integrated AIC" if COMPILE_TEST
+       depends on OF
        select IRQ_DOMAIN
        help
          Support for the J-Core integrated AIC.
index efbf0e4304b7073d5aa12bfa97a1d727aace81b7..2a7a38830a8df3ef08fdeebe6f98cd24191f8808 100644 (file)
@@ -85,7 +85,7 @@ static void nps400_irq_eoi_global(struct irq_data *irqd)
        nps_ack_gic();
 }
 
-static void nps400_irq_eoi(struct irq_data *irqd)
+static void nps400_irq_ack(struct irq_data *irqd)
 {
        unsigned int __maybe_unused irq = irqd_to_hwirq(irqd);
 
@@ -103,7 +103,7 @@ static struct irq_chip nps400_irq_chip_percpu = {
        .name           = "NPS400 IC",
        .irq_mask       = nps400_irq_mask,
        .irq_unmask     = nps400_irq_unmask,
-       .irq_eoi        = nps400_irq_eoi,
+       .irq_ack        = nps400_irq_ack,
 };
 
 static int nps400_irq_map(struct irq_domain *d, unsigned int virq,
@@ -135,7 +135,7 @@ static const struct irq_domain_ops nps400_irq_ops = {
 static int __init nps400_of_init(struct device_node *node,
                                 struct device_node *parent)
 {
-       static struct irq_domain *nps400_root_domain;
+       struct irq_domain *nps400_root_domain;
 
        if (parent) {
                pr_err("DeviceTree incore ic not a root irq controller\n");
index 003495d91f9cfd34ea77eec0b52a4f070e58bfd5..c5dee300e8a3e1a40c30d22bba5e1a968e83a21a 100644 (file)
@@ -1023,7 +1023,7 @@ static void its_free_tables(struct its_node *its)
 
 static int its_alloc_tables(struct its_node *its)
 {
-       u64 typer = readq_relaxed(its->base + GITS_TYPER);
+       u64 typer = gic_read_typer(its->base + GITS_TYPER);
        u32 ids = GITS_TYPER_DEVBITS(typer);
        u64 shr = GITS_BASER_InnerShareable;
        u64 cache = GITS_BASER_WaWb;
@@ -1198,7 +1198,7 @@ static void its_cpu_init_collection(void)
                 * We now have to bind each collection to its target
                 * redistributor.
                 */
-               if (readq_relaxed(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
+               if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
                        /*
                         * This ITS wants the physical address of the
                         * redistributor.
@@ -1208,7 +1208,7 @@ static void its_cpu_init_collection(void)
                        /*
                         * This ITS wants a linear CPU number.
                         */
-                       target = readq_relaxed(gic_data_rdist_rd_base() + GICR_TYPER);
+                       target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER);
                        target = GICR_TYPER_CPU_NUMBER(target) << 16;
                }
 
@@ -1691,7 +1691,7 @@ static int __init its_probe_one(struct resource *res,
        INIT_LIST_HEAD(&its->its_device_list);
        its->base = its_base;
        its->phys_base = res->start;
-       its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
+       its->ite_size = ((gic_read_typer(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
        its->numa_node = numa_node;
 
        its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
@@ -1763,7 +1763,7 @@ out_unmap:
 
 static bool gic_rdists_supports_plpis(void)
 {
-       return !!(readl_relaxed(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
+       return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
 }
 
 int its_cpu_init(void)
index 9b81bd8b929c0bf925d6e3fe578d03b0c2af7afd..19d642eae096b2495f5707470ea5f857d2f9b876 100644 (file)
@@ -153,7 +153,7 @@ static void gic_enable_redist(bool enable)
                        return; /* No PM support in this redistributor */
        }
 
-       while (count--) {
+       while (--count) {
                val = readl_relaxed(rbase + GICR_WAKER);
                if (enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep))
                        break;
index 58e5b4e870561c6361ff50a9e5869cf8abd4e356..d6c404b3584d5118799f8376d384c2f71b728a69 100644 (file)
@@ -1279,7 +1279,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
                 */
                *base += 0xf000;
                cpuif_res.start += 0xf000;
-               pr_warn("GIC: Adjusting CPU interface base to %pa",
+               pr_warn("GIC: Adjusting CPU interface base to %pa\n",
                        &cpuif_res.start);
        }
 
index 84b01dec277dfee6f35c286c43448ed258a48199..033bccb41455c46c32d5473fa46940c2770973e9 100644 (file)
 
 static struct irq_chip jcore_aic;
 
+/*
+ * The J-Core AIC1 and AIC2 are cpu-local interrupt controllers and do
+ * not distinguish or use distinct irq number ranges for per-cpu event
+ * interrupts (timer, IPI). Since information to determine whether a
+ * particular irq number should be treated as per-cpu is not available
+ * at mapping time, we use a wrapper handler function which chooses
+ * the right handler at runtime based on whether IRQF_PERCPU was used
+ * when requesting the irq.
+ */
+
+static void handle_jcore_irq(struct irq_desc *desc)
+{
+       if (irqd_is_per_cpu(irq_desc_get_irq_data(desc)))
+               handle_percpu_irq(desc);
+       else
+               handle_simple_irq(desc);
+}
+
 static int jcore_aic_irqdomain_map(struct irq_domain *d, unsigned int irq,
                                   irq_hw_number_t hwirq)
 {
        struct irq_chip *aic = d->host_data;
 
-       irq_set_chip_and_handler(irq, aic, handle_simple_irq);
+       irq_set_chip_and_handler(irq, aic, handle_jcore_irq);
 
        return 0;
 }
index d1f8ab915b15cc69b5fc9564777d413dad0f8318..b90776ef56ec8d2d35e8b51a79f75c2ecd472ab1 100644 (file)
@@ -755,8 +755,10 @@ static int __init ser_gigaset_init(void)
        driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
                                    GIGASET_MODULENAME, GIGASET_DEVNAME,
                                    &ops, THIS_MODULE);
-       if (!driver)
+       if (!driver) {
+               rc = -ENOMEM;
                goto error;
+       }
 
        rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc);
        if (rc != 0) {
index 9600cd771f1a3a234a3b7c647904f3dbd22385c7..e034ed847ff32ca1fcf0a55e66eebe2171e3d32f 100644 (file)
@@ -1499,6 +1499,7 @@ hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                printk(KERN_INFO
                       "HFC-4S/8S: failed to request address space at 0x%04x\n",
                       hw->iobase);
+               err = -EBUSY;
                goto out;
        }
 
index 08c87fadca8ce610e9baff8706dabe2fb7ac82a4..1f32688c312d717639ecfe7de3ca94b35d31a637 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/mailbox_controller.h>
 #include <linux/mailbox_client.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <acpi/pcc.h>
 
 #include "mailbox.h"
 
@@ -267,6 +268,8 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
        if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
                chan->txdone_method |= TXDONE_BY_ACK;
 
+       spin_unlock_irqrestore(&chan->lock, flags);
+
        if (pcc_doorbell_irq[subspace_id] > 0) {
                int rc;
 
@@ -275,12 +278,11 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
                if (unlikely(rc)) {
                        dev_err(dev, "failed to register PCC interrupt %d\n",
                                pcc_doorbell_irq[subspace_id]);
+                       pcc_mbox_free_channel(chan);
                        chan = ERR_PTR(rc);
                }
        }
 
-       spin_unlock_irqrestore(&chan->lock, flags);
-
        return chan;
 }
 EXPORT_SYMBOL_GPL(pcc_mbox_request_channel);
@@ -304,20 +306,19 @@ void pcc_mbox_free_channel(struct mbox_chan *chan)
                return;
        }
 
+       if (pcc_doorbell_irq[id] > 0)
+               devm_free_irq(chan->mbox->dev, pcc_doorbell_irq[id], chan);
+
        spin_lock_irqsave(&chan->lock, flags);
        chan->cl = NULL;
        chan->active_req = NULL;
        if (chan->txdone_method == (TXDONE_BY_POLL | TXDONE_BY_ACK))
                chan->txdone_method = TXDONE_BY_POLL;
 
-       if (pcc_doorbell_irq[id] > 0)
-               devm_free_irq(chan->mbox->dev, pcc_doorbell_irq[id], chan);
-
        spin_unlock_irqrestore(&chan->lock, flags);
 }
 EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
 
-
 /**
  * pcc_send_data - Called from Mailbox Controller code. Used
  *             here only to ring the channel doorbell. The PCC client
index 8abde6b8cedc4540dac80b73256317fb671dbd69..6d53810963f7531a7e5048dad5c55ef53e8aa914 100644 (file)
@@ -266,7 +266,7 @@ static struct raid_type {
        {"raid10_offset", "raid10 offset (striped mirrors)",        0, 2, 10, ALGORITHM_RAID10_OFFSET},
        {"raid10_near",   "raid10 near (striped mirrors)",          0, 2, 10, ALGORITHM_RAID10_NEAR},
        {"raid10",        "raid10 (striped mirrors)",               0, 2, 10, ALGORITHM_RAID10_DEFAULT},
-       {"raid4",         "raid4 (dedicated last parity disk)",     1, 2, 4,  ALGORITHM_PARITY_N}, /* raid4 layout = raid5_n */
+       {"raid4",         "raid4 (dedicated first parity disk)",    1, 2, 5,  ALGORITHM_PARITY_0}, /* raid4 layout = raid5_0 */
        {"raid5_n",       "raid5 (dedicated last parity disk)",     1, 2, 5,  ALGORITHM_PARITY_N},
        {"raid5_ls",      "raid5 (left symmetric)",                 1, 2, 5,  ALGORITHM_LEFT_SYMMETRIC},
        {"raid5_rs",      "raid5 (right symmetric)",                1, 2, 5,  ALGORITHM_RIGHT_SYMMETRIC},
@@ -2087,11 +2087,11 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
                /*
                 * No takeover/reshaping, because we don't have the extended v1.9.0 metadata
                 */
-               if (le32_to_cpu(sb->level) != mddev->level) {
+               if (le32_to_cpu(sb->level) != mddev->new_level) {
                        DMERR("Reshaping/takeover raid sets not yet supported. (raid level/stripes/size change)");
                        return -EINVAL;
                }
-               if (le32_to_cpu(sb->layout) != mddev->layout) {
+               if (le32_to_cpu(sb->layout) != mddev->new_layout) {
                        DMERR("Reshaping raid sets not yet supported. (raid layout change)");
                        DMERR("  0x%X vs 0x%X", le32_to_cpu(sb->layout), mddev->layout);
                        DMERR("  Old layout: %s w/ %d copies",
@@ -2102,7 +2102,7 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
                              raid10_md_layout_to_copies(mddev->layout));
                        return -EINVAL;
                }
-               if (le32_to_cpu(sb->stripe_sectors) != mddev->chunk_sectors) {
+               if (le32_to_cpu(sb->stripe_sectors) != mddev->new_chunk_sectors) {
                        DMERR("Reshaping raid sets not yet supported. (stripe sectors change)");
                        return -EINVAL;
                }
@@ -2115,6 +2115,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
                        return -EINVAL;
                }
 
+               DMINFO("Discovered old metadata format; upgrading to extended metadata format");
+
                /* Table line is checked vs. authoritative superblock */
                rs_set_new(rs);
        }
@@ -2258,7 +2260,8 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
        if (!mddev->events && super_init_validation(rs, rdev))
                return -EINVAL;
 
-       if (le32_to_cpu(sb->compat_features) != FEATURE_FLAG_SUPPORTS_V190) {
+       if (le32_to_cpu(sb->compat_features) &&
+           le32_to_cpu(sb->compat_features) != FEATURE_FLAG_SUPPORTS_V190) {
                rs->ti->error = "Unable to assemble array: Unknown flag(s) in compatible feature flags";
                return -EINVAL;
        }
@@ -3646,7 +3649,7 @@ static void raid_resume(struct dm_target *ti)
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 9, 0},
+       .version = {1, 9, 1},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,
index bdf1606f67bcfbfcfadcfdc65f2c559c68fff5c9..9a8b71067c6eba52dca7a4050a75cc51199ffbe5 100644 (file)
@@ -145,7 +145,6 @@ static void dispatch_bios(void *context, struct bio_list *bio_list)
 
 struct dm_raid1_bio_record {
        struct mirror *m;
-       /* if details->bi_bdev == NULL, details were not saved */
        struct dm_bio_details details;
        region_t write_region;
 };
@@ -1200,8 +1199,6 @@ static int mirror_map(struct dm_target *ti, struct bio *bio)
        struct dm_raid1_bio_record *bio_record =
          dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record));
 
-       bio_record->details.bi_bdev = NULL;
-
        if (rw == WRITE) {
                /* Save region for mirror_end_io() handler */
                bio_record->write_region = dm_rh_bio_to_region(ms->rh, bio);
@@ -1260,22 +1257,12 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
        }
 
        if (error == -EOPNOTSUPP)
-               goto out;
+               return error;
 
        if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD))
-               goto out;
+               return error;
 
        if (unlikely(error)) {
-               if (!bio_record->details.bi_bdev) {
-                       /*
-                        * There wasn't enough memory to record necessary
-                        * information for a retry or there was no other
-                        * mirror in-sync.
-                        */
-                       DMERR_LIMIT("Mirror read failed.");
-                       return -EIO;
-               }
-
                m = bio_record->m;
 
                DMERR("Mirror read failed from %s. Trying alternative device.",
@@ -1291,7 +1278,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
                        bd = &bio_record->details;
 
                        dm_bio_restore(bd, bio);
-                       bio_record->details.bi_bdev = NULL;
+                       bio->bi_error = 0;
 
                        queue_bio(ms, bio, rw);
                        return DM_ENDIO_INCOMPLETE;
@@ -1299,9 +1286,6 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
                DMERR("All replicated volumes dead, failing I/O");
        }
 
-out:
-       bio_record->details.bi_bdev = NULL;
-
        return error;
 }
 
index dc75bea0d541b3a2892d688c7eaf3093e1168790..1d0d2adc050a5539a4b430bd9e055f99e1abb5d7 100644 (file)
@@ -856,8 +856,11 @@ int dm_old_init_request_queue(struct mapped_device *md)
        kthread_init_worker(&md->kworker);
        md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker,
                                       "kdmwork-%s", dm_device_name(md));
-       if (IS_ERR(md->kworker_task))
-               return PTR_ERR(md->kworker_task);
+       if (IS_ERR(md->kworker_task)) {
+               int error = PTR_ERR(md->kworker_task);
+               md->kworker_task = NULL;
+               return error;
+       }
 
        elv_register_queue(md->queue);
 
index 3e407a9cde1f190baade6d22e78c30ae5b27b438..c4b53b332607bec3f303671da385656713498e04 100644 (file)
@@ -695,37 +695,32 @@ int dm_table_add_target(struct dm_table *t, const char *type,
 
        tgt->type = dm_get_target_type(type);
        if (!tgt->type) {
-               DMERR("%s: %s: unknown target type", dm_device_name(t->md),
-                     type);
+               DMERR("%s: %s: unknown target type", dm_device_name(t->md), type);
                return -EINVAL;
        }
 
        if (dm_target_needs_singleton(tgt->type)) {
                if (t->num_targets) {
-                       DMERR("%s: target type %s must appear alone in table",
-                             dm_device_name(t->md), type);
-                       return -EINVAL;
+                       tgt->error = "singleton target type must appear alone in table";
+                       goto bad;
                }
                t->singleton = true;
        }
 
        if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) {
-               DMERR("%s: target type %s may not be included in read-only tables",
-                     dm_device_name(t->md), type);
-               return -EINVAL;
+               tgt->error = "target type may not be included in a read-only table";
+               goto bad;
        }
 
        if (t->immutable_target_type) {
                if (t->immutable_target_type != tgt->type) {
-                       DMERR("%s: immutable target type %s cannot be mixed with other target types",
-                             dm_device_name(t->md), t->immutable_target_type->name);
-                       return -EINVAL;
+                       tgt->error = "immutable target type cannot be mixed with other target types";
+                       goto bad;
                }
        } else if (dm_target_is_immutable(tgt->type)) {
                if (t->num_targets) {
-                       DMERR("%s: immutable target type %s cannot be mixed with other target types",
-                             dm_device_name(t->md), tgt->type->name);
-                       return -EINVAL;
+                       tgt->error = "immutable target type cannot be mixed with other target types";
+                       goto bad;
                }
                t->immutable_target_type = tgt->type;
        }
@@ -740,7 +735,6 @@ int dm_table_add_target(struct dm_table *t, const char *type,
         */
        if (!adjoin(t, tgt)) {
                tgt->error = "Gap in table";
-               r = -EINVAL;
                goto bad;
        }
 
index 147af9536d0c10d4054f42306383e6fe118a6ce4..ef7bf1dd6900893c8faf728cb57a93ad8b17af54 100644 (file)
@@ -1423,8 +1423,6 @@ static void cleanup_mapped_device(struct mapped_device *md)
        if (md->bs)
                bioset_free(md->bs);
 
-       cleanup_srcu_struct(&md->io_barrier);
-
        if (md->disk) {
                spin_lock(&_minor_lock);
                md->disk->private_data = NULL;
@@ -1436,6 +1434,8 @@ static void cleanup_mapped_device(struct mapped_device *md)
        if (md->queue)
                blk_cleanup_queue(md->queue);
 
+       cleanup_srcu_struct(&md->io_barrier);
+
        if (md->bdev) {
                bdput(md->bdev);
                md->bdev = NULL;
index eac84d8ff7244b659bef2ccea8c8f4ada8b7bc2f..2089d46b0eb89cf280bd6d90202a9caaeff13d47 100644 (file)
@@ -3887,10 +3887,10 @@ array_state_show(struct mddev *mddev, char *page)
                        st = read_auto;
                        break;
                case 0:
-                       if (mddev->in_sync)
-                               st = clean;
-                       else if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
+                       if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
                                st = write_pending;
+                       else if (mddev->in_sync)
+                               st = clean;
                        else if (mddev->safemode)
                                st = active_idle;
                        else
@@ -8144,14 +8144,14 @@ void md_do_sync(struct md_thread *thread)
 
        if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
            !test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
-           mddev->curr_resync > 2) {
+           mddev->curr_resync > 3) {
                mddev->curr_resync_completed = mddev->curr_resync;
                sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        }
        mddev->pers->sync_request(mddev, max_sectors, &skipped);
 
        if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
-           mddev->curr_resync > 2) {
+           mddev->curr_resync > 3) {
                if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
                        if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
                                if (mddev->curr_resync >= mddev->recovery_cp) {
index 1961d827dbd19b5bbe2f4dbee356ac1f2a29fea7..29e2df5cd77b282fd4dd0cff8aa5599d7aacc7ef 100644 (file)
@@ -403,11 +403,14 @@ static void raid1_end_write_request(struct bio *bio)
        struct bio *to_put = NULL;
        int mirror = find_bio_disk(r1_bio, bio);
        struct md_rdev *rdev = conf->mirrors[mirror].rdev;
+       bool discard_error;
+
+       discard_error = bio->bi_error && bio_op(bio) == REQ_OP_DISCARD;
 
        /*
         * 'one mirror IO has finished' event handler:
         */
-       if (bio->bi_error) {
+       if (bio->bi_error && !discard_error) {
                set_bit(WriteErrorSeen, &rdev->flags);
                if (!test_and_set_bit(WantReplacement, &rdev->flags))
                        set_bit(MD_RECOVERY_NEEDED, &
@@ -444,7 +447,7 @@ static void raid1_end_write_request(struct bio *bio)
 
                /* Maybe we can clear some bad blocks. */
                if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors,
-                               &first_bad, &bad_sectors)) {
+                               &first_bad, &bad_sectors) && !discard_error) {
                        r1_bio->bios[mirror] = IO_MADE_GOOD;
                        set_bit(R1BIO_MadeGood, &r1_bio->state);
                }
@@ -2294,17 +2297,23 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
         * This is all done synchronously while the array is
         * frozen
         */
+
+       bio = r1_bio->bios[r1_bio->read_disk];
+       bdevname(bio->bi_bdev, b);
+       bio_put(bio);
+       r1_bio->bios[r1_bio->read_disk] = NULL;
+
        if (mddev->ro == 0) {
                freeze_array(conf, 1);
                fix_read_error(conf, r1_bio->read_disk,
                               r1_bio->sector, r1_bio->sectors);
                unfreeze_array(conf);
-       } else
-               md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
+       } else {
+               r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+       }
+
        rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev);
 
-       bio = r1_bio->bios[r1_bio->read_disk];
-       bdevname(bio->bi_bdev, b);
 read_more:
        disk = read_balance(conf, r1_bio, &max_sectors);
        if (disk == -1) {
@@ -2315,11 +2324,6 @@ read_more:
        } else {
                const unsigned long do_sync
                        = r1_bio->master_bio->bi_opf & REQ_SYNC;
-               if (bio) {
-                       r1_bio->bios[r1_bio->read_disk] =
-                               mddev->ro ? IO_BLOCKED : NULL;
-                       bio_put(bio);
-               }
                r1_bio->read_disk = disk;
                bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev);
                bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector,
index be1a9fca3b2d2ade369359d109d1a53ddf30d077..39fddda2fef2d918863699e3f283f441f6fb52c1 100644 (file)
@@ -447,6 +447,9 @@ static void raid10_end_write_request(struct bio *bio)
        struct r10conf *conf = r10_bio->mddev->private;
        int slot, repl;
        struct md_rdev *rdev = NULL;
+       bool discard_error;
+
+       discard_error = bio->bi_error && bio_op(bio) == REQ_OP_DISCARD;
 
        dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
 
@@ -460,7 +463,7 @@ static void raid10_end_write_request(struct bio *bio)
        /*
         * this branch is our 'one mirror IO has finished' event handler:
         */
-       if (bio->bi_error) {
+       if (bio->bi_error && !discard_error) {
                if (repl)
                        /* Never record new bad blocks to replacement,
                         * just fail it.
@@ -503,7 +506,7 @@ static void raid10_end_write_request(struct bio *bio)
                if (is_badblock(rdev,
                                r10_bio->devs[slot].addr,
                                r10_bio->sectors,
-                               &first_bad, &bad_sectors)) {
+                               &first_bad, &bad_sectors) && !discard_error) {
                        bio_put(bio);
                        if (repl)
                                r10_bio->devs[slot].repl_bio = IO_MADE_GOOD;
index 1b1ab4a1d132b39f0145b8bc3305484fad5a7091..a227a9f3ee6556b1af15223080e791fda7817989 100644 (file)
@@ -1087,7 +1087,7 @@ static int r5l_recovery_log(struct r5l_log *log)
         * 1's seq + 10 and let superblock points to meta2. The same recovery will
         * not think meta 3 is a valid meta, because its seq doesn't match
         */
-       if (ctx.seq > log->last_cp_seq + 1) {
+       if (ctx.seq > log->last_cp_seq) {
                int ret;
 
                ret = r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq + 10);
@@ -1096,6 +1096,8 @@ static int r5l_recovery_log(struct r5l_log *log)
                log->seq = ctx.seq + 11;
                log->log_start = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
                r5l_write_super(log, ctx.pos);
+               log->last_checkpoint = ctx.pos;
+               log->next_checkpoint = ctx.pos;
        } else {
                log->log_start = ctx.pos;
                log->seq = ctx.seq;
@@ -1154,6 +1156,7 @@ create:
        if (create_super) {
                log->last_cp_seq = prandom_u32();
                cp = 0;
+               r5l_log_write_empty_meta_block(log, cp, log->last_cp_seq);
                /*
                 * Make sure super points to correct address. Log might have
                 * data very soon. If super hasn't correct log tail address,
@@ -1168,6 +1171,7 @@ create:
        if (log->max_free_space > RECLAIM_MAX_FREE_SPACE)
                log->max_free_space = RECLAIM_MAX_FREE_SPACE;
        log->last_checkpoint = cp;
+       log->next_checkpoint = cp;
 
        __free_page(page);
 
index 012225587c258abb18f6946e31757112ca7f8981..b71b747ee0baae22a68c081b24132bef5f05bf2a 100644 (file)
@@ -513,6 +513,11 @@ config DVB_AS102_FE
        depends on DVB_CORE
        default DVB_AS102
 
+config DVB_GP8PSK_FE
+       tristate
+       depends on DVB_CORE
+       default DVB_USB_GP8PSK
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
index e90165ad361bbae7324cb966a1d668187be471ca..93921a4eaa275997a5ed4178de1acb1a54409430 100644 (file)
@@ -121,6 +121,7 @@ obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
 obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o
+obj-$(CONFIG_DVB_GP8PSK_FE) += gp8psk-fe.o
 obj-$(CONFIG_DVB_TC90522) += tc90522.o
 obj-$(CONFIG_DVB_HORUS3A) += horus3a.o
 obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o
similarity index 69%
rename from drivers/media/usb/dvb-usb/gp8psk-fe.c
rename to drivers/media/dvb-frontends/gp8psk-fe.c
index db6eb79cde0737deba4d841da8ad85289c658282..93f59bfea092cebfc9df16fe9e01a9a913c2328b 100644 (file)
@@ -1,5 +1,5 @@
-/* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
+/*
+ * Frontend driver for the GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
  *
  * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
  * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
@@ -8,17 +8,31 @@
  *
  * This module is based off the vp7045 and vp702x modules
  *
- *     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.
- *
- * see Documentation/dvb/README.dvb-usb for more information
+ * 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.
  */
-#include "gp8psk.h"
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "gp8psk-fe.h"
+#include "dvb_frontend.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(fmt, arg...) do {                                      \
+       if (debug)                                                      \
+               printk(KERN_DEBUG pr_fmt("%s: " fmt),                   \
+                      __func__, ##arg);                                \
+} while (0)
 
 struct gp8psk_fe_state {
        struct dvb_frontend fe;
-       struct dvb_usb_device *d;
+       void *priv;
+       const struct gp8psk_fe_ops *ops;
+       bool is_rev1;
        u8 lock;
        u16 snr;
        unsigned long next_status_check;
@@ -29,22 +43,24 @@ static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
 {
        struct gp8psk_fe_state *st = fe->demodulator_priv;
        u8 status;
-       gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
+
+       st->ops->in(st->priv, GET_8PSK_CONFIG, 0, 0, &status, 1);
        return status & bmDCtuned;
 }
 
 static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
 {
-       struct gp8psk_fe_state *state = fe->demodulator_priv;
-       return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+       return st->ops->out(st->priv, SET_8PSK_CONFIG, mode, 0, NULL, 0);
 }
 
 static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
 {
        u8 buf[6];
        if (time_after(jiffies,st->next_status_check)) {
-               gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
-               gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
+               st->ops->in(st->priv, GET_SIGNAL_LOCK, 0, 0, &st->lock, 1);
+               st->ops->in(st->priv, GET_SIGNAL_STRENGTH, 0, 0, buf, 6);
                st->snr = (buf[1]) << 8 | buf[0];
                st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
        }
@@ -116,13 +132,12 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
 
 static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
 {
-       struct gp8psk_fe_state *state = fe->demodulator_priv;
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u8 cmd[10];
        u32 freq = c->frequency * 1000;
-       int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
 
-       deb_fe("%s()\n", __func__);
+       dprintk("%s()\n", __func__);
 
        cmd[4] = freq         & 0xff;
        cmd[5] = (freq >> 8)  & 0xff;
@@ -136,21 +151,21 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
        switch (c->delivery_system) {
        case SYS_DVBS:
                if (c->modulation != QPSK) {
-                       deb_fe("%s: unsupported modulation selected (%d)\n",
+                       dprintk("%s: unsupported modulation selected (%d)\n",
                                __func__, c->modulation);
                        return -EOPNOTSUPP;
                }
                c->fec_inner = FEC_AUTO;
                break;
        case SYS_DVBS2: /* kept for backwards compatibility */
-               deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
+               dprintk("%s: DVB-S2 delivery system selected\n", __func__);
                break;
        case SYS_TURBO:
-               deb_fe("%s: Turbo-FEC delivery system selected\n", __func__);
+               dprintk("%s: Turbo-FEC delivery system selected\n", __func__);
                break;
 
        default:
-               deb_fe("%s: unsupported delivery system selected (%d)\n",
+               dprintk("%s: unsupported delivery system selected (%d)\n",
                        __func__, c->delivery_system);
                return -EOPNOTSUPP;
        }
@@ -161,9 +176,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
        cmd[3] = (c->symbol_rate >> 24) & 0xff;
        switch (c->modulation) {
        case QPSK:
-               if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+               if (st->is_rev1)
                        if (gp8psk_tuned_to_DCII(fe))
-                               gp8psk_bcm4500_reload(state->d);
+                               st->ops->reload(st->priv);
                switch (c->fec_inner) {
                case FEC_1_2:
                        cmd[9] = 0; break;
@@ -207,18 +222,18 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
                cmd[9] = 0;
                break;
        default: /* Unknown modulation */
-               deb_fe("%s: unsupported modulation selected (%d)\n",
+               dprintk("%s: unsupported modulation selected (%d)\n",
                        __func__, c->modulation);
                return -EOPNOTSUPP;
        }
 
-       if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+       if (st->is_rev1)
                gp8psk_set_tuner_mode(fe, 0);
-       gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
+       st->ops->out(st->priv, TUNE_8PSK, 0, 0, cmd, 10);
 
-       state->lock = 0;
-       state->next_status_check = jiffies;
-       state->status_check_interval = 200;
+       st->lock = 0;
+       st->next_status_check = jiffies;
+       st->status_check_interval = 200;
 
        return 0;
 }
@@ -228,9 +243,9 @@ static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
 {
        struct gp8psk_fe_state *st = fe->demodulator_priv;
 
-       deb_fe("%s\n",__func__);
+       dprintk("%s\n", __func__);
 
-       if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+       if (st->ops->out(st->priv, SEND_DISEQC_COMMAND, m->msg[0], 0,
                        m->msg, m->msg_len)) {
                return -EINVAL;
        }
@@ -243,12 +258,12 @@ static int gp8psk_fe_send_diseqc_burst(struct dvb_frontend *fe,
        struct gp8psk_fe_state *st = fe->demodulator_priv;
        u8 cmd;
 
-       deb_fe("%s\n",__func__);
+       dprintk("%s\n", __func__);
 
        /* These commands are certainly wrong */
        cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
 
-       if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+       if (st->ops->out(st->priv, SEND_DISEQC_COMMAND, cmd, 0,
                        &cmd, 0)) {
                return -EINVAL;
        }
@@ -258,10 +273,10 @@ static int gp8psk_fe_send_diseqc_burst(struct dvb_frontend *fe,
 static int gp8psk_fe_set_tone(struct dvb_frontend *fe,
                              enum fe_sec_tone_mode tone)
 {
-       struct gp8psk_fe_state* state = fe->demodulator_priv;
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
 
-       if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
-                (tone == SEC_TONE_ON), 0, NULL, 0)) {
+       if (st->ops->out(st->priv, SET_22KHZ_TONE,
+                        (tone == SEC_TONE_ON), 0, NULL, 0)) {
                return -EINVAL;
        }
        return 0;
@@ -270,9 +285,9 @@ static int gp8psk_fe_set_tone(struct dvb_frontend *fe,
 static int gp8psk_fe_set_voltage(struct dvb_frontend *fe,
                                 enum fe_sec_voltage voltage)
 {
-       struct gp8psk_fe_state* state = fe->demodulator_priv;
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
 
-       if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+       if (st->ops->out(st->priv, SET_LNB_VOLTAGE,
                         voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
                return -EINVAL;
        }
@@ -281,52 +296,60 @@ static int gp8psk_fe_set_voltage(struct dvb_frontend *fe,
 
 static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
 {
-       struct gp8psk_fe_state* state = fe->demodulator_priv;
-       return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+       return st->ops->out(st->priv, USE_EXTRA_VOLT, onoff, 0, NULL, 0);
 }
 
 static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
 {
-       struct gp8psk_fe_state* state = fe->demodulator_priv;
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
        u8 cmd = sw_cmd & 0x7f;
 
-       if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
-                       NULL, 0)) {
+       if (st->ops->out(st->priv, SET_DN_SWITCH, cmd, 0, NULL, 0))
                return -EINVAL;
-       }
-       if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
-                       0, NULL, 0)) {
+
+       if (st->ops->out(st->priv, SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+                       0, NULL, 0))
                return -EINVAL;
-       }
 
        return 0;
 }
 
 static void gp8psk_fe_release(struct dvb_frontend* fe)
 {
-       struct gp8psk_fe_state *state = fe->demodulator_priv;
-       kfree(state);
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+       kfree(st);
 }
 
 static struct dvb_frontend_ops gp8psk_fe_ops;
 
-struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+struct dvb_frontend *gp8psk_fe_attach(const struct gp8psk_fe_ops *ops,
+                                     void *priv, bool is_rev1)
 {
-       struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
-       if (s == NULL)
-               goto error;
-
-       s->d = d;
-       memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
-       s->fe.demodulator_priv = s;
-
-       goto success;
-error:
-       return NULL;
-success:
-       return &s->fe;
-}
+       struct gp8psk_fe_state *st;
 
+       if (!ops || !ops->in || !ops->out || !ops->reload) {
+               pr_err("Error! gp8psk-fe ops not defined.\n");
+               return NULL;
+       }
+
+       st = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+       if (!st)
+               return NULL;
+
+       memcpy(&st->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+       st->fe.demodulator_priv = st;
+       st->ops = ops;
+       st->priv = priv;
+       st->is_rev1 = is_rev1;
+
+       pr_info("Frontend %sattached\n", is_rev1 ? "revision 1 " : "");
+
+       return &st->fe;
+}
+EXPORT_SYMBOL_GPL(gp8psk_fe_attach);
 
 static struct dvb_frontend_ops gp8psk_fe_ops = {
        .delsys = { SYS_DVBS },
@@ -370,3 +393,8 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
        .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
        .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
 };
+
+MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
+MODULE_DESCRIPTION("Frontend Driver for Genpix DVB-S");
+MODULE_VERSION("1.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/gp8psk-fe.h b/drivers/media/dvb-frontends/gp8psk-fe.h
new file mode 100644 (file)
index 0000000..6c7944b
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * gp8psk_fe driver
+ *
+ * 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, 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 GP8PSK_FE_H
+#define GP8PSK_FE_H
+
+#include <linux/types.h>
+
+/* gp8psk commands */
+
+#define GET_8PSK_CONFIG                 0x80    /* in */
+#define SET_8PSK_CONFIG                 0x81
+#define I2C_WRITE                      0x83
+#define I2C_READ                       0x84
+#define ARM_TRANSFER                    0x85
+#define TUNE_8PSK                       0x86
+#define GET_SIGNAL_STRENGTH             0x87    /* in */
+#define LOAD_BCM4500                    0x88
+#define BOOT_8PSK                       0x89    /* in */
+#define START_INTERSIL                  0x8A    /* in */
+#define SET_LNB_VOLTAGE                 0x8B
+#define SET_22KHZ_TONE                  0x8C
+#define SEND_DISEQC_COMMAND             0x8D
+#define SET_DVB_MODE                    0x8E
+#define SET_DN_SWITCH                   0x8F
+#define GET_SIGNAL_LOCK                 0x90    /* in */
+#define GET_FW_VERS                    0x92
+#define GET_SERIAL_NUMBER               0x93    /* in */
+#define USE_EXTRA_VOLT                  0x94
+#define GET_FPGA_VERS                  0x95
+#define CW3K_INIT                      0x9d
+
+/* PSK_configuration bits */
+#define bm8pskStarted                   0x01
+#define bm8pskFW_Loaded                 0x02
+#define bmIntersilOn                    0x04
+#define bmDVBmode                       0x08
+#define bm22kHz                         0x10
+#define bmSEL18V                        0x20
+#define bmDCtuned                       0x40
+#define bmArmed                         0x80
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1   /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2   /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3  /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4  /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5  /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6  /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8     /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
+
+/* firmware revision id's */
+#define GP8PSK_FW_REV1                 0x020604
+#define GP8PSK_FW_REV2                 0x020704
+#define GP8PSK_FW_VERS(_fw_vers) \
+       ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0])
+
+struct gp8psk_fe_ops {
+       int (*in)(void *priv, u8 req, u16 value, u16 index, u8 *b, int blen);
+       int (*out)(void *priv, u8 req, u16 value, u16 index, u8 *b, int blen);
+       int (*reload)(void *priv);
+};
+
+struct dvb_frontend *gp8psk_fe_attach(const struct gp8psk_fe_ops *ops,
+                                     void *priv, bool is_rev1);
+
+#endif
index f95a6bc839d58f5f6cde8c37170f297f24ca8b3b..cede3975d04bd90441abcb29e6f169857561f935 100644 (file)
@@ -118,7 +118,7 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol,
                        *protocol = RC_TYPE_RC6_MCE;
                        dev &= 0x7f;
                        dprintk(1, "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n",
-                                               toggle, vendor, dev, code);
+                                               *ptoggle, vendor, dev, code);
                } else {
                        *ptoggle = 0;
                        *protocol = RC_TYPE_RC6_6A_32;
index 4769469fe842964574eae3a72b812f579ab5f63f..2c9232ef7baa4b57efd020547d0b2af3f42199d4 100644 (file)
@@ -124,8 +124,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
        }
 
        /* Get user pages for DMA Xfer */
-       err = get_user_pages_unlocked(user_dma.uaddr, user_dma.page_count, 0,
-                       1, dma->map);
+       err = get_user_pages_unlocked(user_dma.uaddr, user_dma.page_count,
+                       dma->map, FOLL_FORCE);
 
        if (user_dma.page_count != err) {
                IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
index b094054cda6e55b64852598d6d22dd6d57e6cdaa..f7299d3d82449ddaefc1ee76fd3f8cb33650e5b4 100644 (file)
@@ -76,11 +76,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 
        /* Get user pages for DMA Xfer */
        y_pages = get_user_pages_unlocked(y_dma.uaddr,
-                       y_dma.page_count, 0, 1, &dma->map[0]);
+                       y_dma.page_count, &dma->map[0], FOLL_FORCE);
        uv_pages = 0; /* silence gcc. value is set and consumed only if: */
        if (y_pages == y_dma.page_count) {
                uv_pages = get_user_pages_unlocked(uv_dma.uaddr,
-                               uv_dma.page_count, 0, 1, &dma->map[y_pages]);
+                               uv_dma.page_count, &dma->map[y_pages],
+                               FOLL_FORCE);
        }
 
        if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
index e668dde6d85722d2b68d7f399452d22bbf6d8342..a31b95cb3b09c0623be42762cea8d4dc08c99170 100644 (file)
@@ -214,7 +214,7 @@ static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
        if (!vec)
                return -ENOMEM;
 
-       ret = get_vaddr_frames(virtp, 1, true, false, vec);
+       ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec);
        if (ret != 1) {
                frame_vector_destroy(vec);
                return -EINVAL;
index 317ef63ee78999d673f85b62af14bed7e664549e..8d96a22647b396c5a8790775a883ff58eabce7ce 100644 (file)
@@ -281,6 +281,14 @@ static void free_firmware(struct xc2028_data *priv)
        int i;
        tuner_dbg("%s called\n", __func__);
 
+       /* free allocated f/w string */
+       if (priv->fname != firmware_name)
+               kfree(priv->fname);
+       priv->fname = NULL;
+
+       priv->state = XC2028_NO_FIRMWARE;
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
        if (!priv->firm)
                return;
 
@@ -291,9 +299,6 @@ static void free_firmware(struct xc2028_data *priv)
 
        priv->firm = NULL;
        priv->firm_size = 0;
-       priv->state = XC2028_NO_FIRMWARE;
-
-       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 }
 
 static int load_all_firmwares(struct dvb_frontend *fe,
@@ -884,9 +889,8 @@ read_not_reliable:
        return 0;
 
 fail:
-       priv->state = XC2028_NO_FIRMWARE;
+       free_firmware(priv);
 
-       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
        if (retry_count < 8) {
                msleep(50);
                retry_count++;
@@ -1332,11 +1336,8 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
        mutex_lock(&xc2028_list_mutex);
 
        /* only perform final cleanup if this is the last instance */
-       if (hybrid_tuner_report_instance_count(priv) == 1) {
+       if (hybrid_tuner_report_instance_count(priv) == 1)
                free_firmware(priv);
-               kfree(priv->ctrl.fname);
-               priv->ctrl.fname = NULL;
-       }
 
        if (priv)
                hybrid_tuner_release_state(priv);
@@ -1399,19 +1400,8 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
 
        /*
         * Copy the config data.
-        * For the firmware name, keep a local copy of the string,
-        * in order to avoid troubles during device release.
         */
-       kfree(priv->ctrl.fname);
-       priv->ctrl.fname = NULL;
        memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
-       if (p->fname) {
-               priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
-               if (priv->ctrl.fname == NULL) {
-                       rc = -ENOMEM;
-                       goto unlock;
-               }
-       }
 
        /*
         * If firmware name changed, frees firmware. As free_firmware will
@@ -1426,10 +1416,15 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
 
        if (priv->state == XC2028_NO_FIRMWARE) {
                if (!firmware_name[0])
-                       priv->fname = priv->ctrl.fname;
+                       priv->fname = kstrdup(p->fname, GFP_KERNEL);
                else
                        priv->fname = firmware_name;
 
+               if (!priv->fname) {
+                       rc = -ENOMEM;
+                       goto unlock;
+               }
+
                rc = request_firmware_nowait(THIS_MODULE, 1,
                                             priv->fname,
                                             priv->i2c_props.adap->dev.parent,
index d4bdba60b0f71436065e4884d5622cc34dffbfe6..52bc42da8a4ce4dde4848c3a2497c5b286b6ae8b 100644 (file)
@@ -73,23 +73,34 @@ static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI,
        u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
        u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
                (read ? 0x80 : 0);
+       int ret;
+
+       mutex_lock(&fc_usb->data_mutex);
+       if (!read)
+               memcpy(fc_usb->data, val, sizeof(*val));
 
-       int len = usb_control_msg(fc_usb->udev,
+       ret = usb_control_msg(fc_usb->udev,
                        read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
                        request,
                        request_type, /* 0xc0 read or 0x40 write */
                        wAddress,
                        0,
-                       val,
+                       fc_usb->data,
                        sizeof(u32),
                        B2C2_WAIT_FOR_OPERATION_RDW * HZ);
 
-       if (len != sizeof(u32)) {
+       if (ret != sizeof(u32)) {
                err("error while %s dword from %d (%d).", read ? "reading" :
                                "writing", wAddress, wRegOffsPCI);
-               return -EIO;
+               if (ret >= 0)
+                       ret = -EIO;
        }
-       return 0;
+
+       if (read && ret >= 0)
+               memcpy(val, fc_usb->data, sizeof(*val));
+       mutex_unlock(&fc_usb->data_mutex);
+
+       return ret;
 }
 /*
  * DKT 010817 - add support for V8 memory read/write and flash update
@@ -100,9 +111,14 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
 {
        u8 request_type = USB_TYPE_VENDOR;
        u16 wIndex;
-       int nWaitTime, pipe, len;
+       int nWaitTime, pipe, ret;
        wIndex = page << 8;
 
+       if (buflen > sizeof(fc_usb->data)) {
+               err("Buffer size bigger than max URB control message\n");
+               return -EIO;
+       }
+
        switch (req) {
        case B2C2_USB_READ_V8_MEM:
                nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
@@ -127,17 +143,32 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
        deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
                        wAddress, wIndex, buflen);
 
-       len = usb_control_msg(fc_usb->udev, pipe,
+       mutex_lock(&fc_usb->data_mutex);
+
+       if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+               memcpy(fc_usb->data, pbBuffer, buflen);
+
+       ret = usb_control_msg(fc_usb->udev, pipe,
                        req,
                        request_type,
                        wAddress,
                        wIndex,
-                       pbBuffer,
+                       fc_usb->data,
                        buflen,
                        nWaitTime * HZ);
+       if (ret != buflen)
+               ret = -EIO;
+
+       if (ret >= 0) {
+               ret = 0;
+               if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+                       memcpy(pbBuffer, fc_usb->data, buflen);
+       }
 
-       debug_dump(pbBuffer, len, deb_v8);
-       return len == buflen ? 0 : -EIO;
+       mutex_unlock(&fc_usb->data_mutex);
+
+       debug_dump(pbBuffer, ret, deb_v8);
+       return ret;
 }
 
 #define bytes_left_to_read_on_page(paddr,buflen) \
@@ -196,29 +227,6 @@ static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
                fc->dvb_adapter.proposed_mac, 6);
 }
 
-#if 0
-static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
-               flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
-               u16 buflen, u8 *pvBuffer)
-{
-       u16 wValue;
-       u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
-       int nWaitTime = 2,
-           pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
-       wValue = (func << 8) | extra;
-
-       len = usb_control_msg(fc_usb->udev,pipe,
-                       B2C2_USB_UTILITY,
-                       request_type,
-                       wValue,
-                       wIndex,
-                       pvBuffer,
-                       buflen,
-                       nWaitTime * HZ);
-       return len == buflen ? 0 : -EIO;
-}
-#endif
-
 /* usb i2c stuff */
 static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
                flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
@@ -226,9 +234,14 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
 {
        struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
        u16 wValue, wIndex;
-       int nWaitTime,pipe,len;
+       int nWaitTime, pipe, ret;
        u8 request_type = USB_TYPE_VENDOR;
 
+       if (buflen > sizeof(fc_usb->data)) {
+               err("Buffer size bigger than max URB control message\n");
+               return -EIO;
+       }
+
        switch (func) {
        case USB_FUNC_I2C_WRITE:
        case USB_FUNC_I2C_MULTIWRITE:
@@ -257,15 +270,32 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
                        wValue & 0xff, wValue >> 8,
                        wIndex & 0xff, wIndex >> 8);
 
-       len = usb_control_msg(fc_usb->udev,pipe,
+       mutex_lock(&fc_usb->data_mutex);
+
+       if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+               memcpy(fc_usb->data, buf, buflen);
+
+       ret = usb_control_msg(fc_usb->udev, pipe,
                        req,
                        request_type,
                        wValue,
                        wIndex,
-                       buf,
+                       fc_usb->data,
                        buflen,
                        nWaitTime * HZ);
-       return len == buflen ? 0 : -EREMOTEIO;
+
+       if (ret != buflen)
+               ret = -EIO;
+
+       if (ret >= 0) {
+               ret = 0;
+               if ((request_type & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+                       memcpy(buf, fc_usb->data, buflen);
+       }
+
+       mutex_unlock(&fc_usb->data_mutex);
+
+       return 0;
 }
 
 /* actual bus specific access functions,
@@ -516,6 +546,7 @@ static int flexcop_usb_probe(struct usb_interface *intf,
        /* general flexcop init */
        fc_usb = fc->bus_specific;
        fc_usb->fc_dev = fc;
+       mutex_init(&fc_usb->data_mutex);
 
        fc->read_ibi_reg  = flexcop_usb_read_ibi_reg;
        fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
index 92529a9c4475b71ca5381670ceb16d5ccfcd079c..25ad43166e78c759226c603e66fa6e6b81a361f8 100644 (file)
@@ -29,6 +29,10 @@ struct flexcop_usb {
 
        u8 tmp_buffer[1023+190];
        int tmp_buffer_length;
+
+       /* for URB control messages */
+       u8 data[80];
+       struct mutex data_mutex;
 };
 
 #if 0
index 13620cdf05996fd3d549a5668043db0b12b1d381..e9100a23583104d3f6fcdcb4f0dfa9535877704a 100644 (file)
@@ -545,18 +545,30 @@ static void free_sbufs(struct camera_data *cam)
 static int write_packet(struct usb_device *udev,
                        u8 request, u8 * registers, u16 start, size_t size)
 {
+       unsigned char *buf;
+       int ret;
+
        if (!registers || size <= 0)
                return -EINVAL;
 
-       return usb_control_msg(udev,
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       memcpy(buf, registers, size);
+
+       ret = usb_control_msg(udev,
                               usb_sndctrlpipe(udev, 0),
                               request,
                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                               start,   /* value */
                               0,       /* index */
-                              registers,       /* buffer */
+                              buf,     /* buffer */
                               size,
                               HZ);
+
+       kfree(buf);
+       return ret;
 }
 
 /****************************************************************************
@@ -567,18 +579,32 @@ static int write_packet(struct usb_device *udev,
 static int read_packet(struct usb_device *udev,
                       u8 request, u8 * registers, u16 start, size_t size)
 {
+       unsigned char *buf;
+       int ret;
+
        if (!registers || size <= 0)
                return -EINVAL;
 
-       return usb_control_msg(udev,
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(udev,
                               usb_rcvctrlpipe(udev, 0),
                               request,
                               USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
                               start,   /* value */
                               0,       /* index */
-                              registers,       /* buffer */
+                              buf,     /* buffer */
                               size,
                               HZ);
+
+       if (ret >= 0)
+               memcpy(registers, buf, size);
+
+       kfree(buf);
+
+       return ret;
 }
 
 /******************************************************************************
index 2a7b5a963acfd902f832e8af5f7fbaa9f0f4a76c..3b3f32b426d192af84b874c0c329ce52bb8baec7 100644 (file)
@@ -8,7 +8,7 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
 dvb-usb-vp702x-objs := vp702x.o vp702x-fe.o
 obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
 
-dvb-usb-gp8psk-objs := gp8psk.o gp8psk-fe.o
+dvb-usb-gp8psk-objs := gp8psk.o
 obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
 
 dvb-usb-dtt200u-objs := dtt200u.o dtt200u-fe.o
index efa782ed6e2d833630f7984646a7ddd2a6a90bdb..7853261906b1afd3334e8e67e74a3f4a5311a13e 100644 (file)
@@ -52,17 +52,15 @@ u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
 struct af9005_device_state {
        u8 sequence;
        int led_state;
+       unsigned char data[256];
 };
 
 static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
                              int readwrite, int type, u8 * values, int len)
 {
        struct af9005_device_state *st = d->priv;
-       u8 obuf[16] = { 0 };
-       u8 ibuf[17] = { 0 };
-       u8 command;
-       int i;
-       int ret;
+       u8 command, seq;
+       int i, ret;
 
        if (len < 1) {
                err("generic read/write, less than 1 byte. Makes no sense.");
@@ -73,16 +71,17 @@ static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
                return -EINVAL;
        }
 
-       obuf[0] = 14;           /* rest of buffer length low */
-       obuf[1] = 0;            /* rest of buffer length high */
+       mutex_lock(&d->data_mutex);
+       st->data[0] = 14;               /* rest of buffer length low */
+       st->data[1] = 0;                /* rest of buffer length high */
 
-       obuf[2] = AF9005_REGISTER_RW;   /* register operation */
-       obuf[3] = 12;           /* rest of buffer length */
+       st->data[2] = AF9005_REGISTER_RW;       /* register operation */
+       st->data[3] = 12;               /* rest of buffer length */
 
-       obuf[4] = st->sequence++;       /* sequence number */
+       st->data[4] = seq = st->sequence++;     /* sequence number */
 
-       obuf[5] = (u8) (reg >> 8);      /* register address */
-       obuf[6] = (u8) (reg & 0xff);
+       st->data[5] = (u8) (reg >> 8);  /* register address */
+       st->data[6] = (u8) (reg & 0xff);
 
        if (type == AF9005_OFDM_REG) {
                command = AF9005_CMD_OFDM_REG;
@@ -96,51 +95,52 @@ static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
        command |= readwrite;
        if (readwrite == AF9005_CMD_WRITE)
                for (i = 0; i < len; i++)
-                       obuf[8 + i] = values[i];
+                       st->data[8 + i] = values[i];
        else if (type == AF9005_TUNER_REG)
                /* read command for tuner, the first byte contains the i2c address */
-               obuf[8] = values[0];
-       obuf[7] = command;
+               st->data[8] = values[0];
+       st->data[7] = command;
 
-       ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+       ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 17, 0);
        if (ret)
-               return ret;
+               goto ret;
 
        /* sanity check */
-       if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+       if (st->data[2] != AF9005_REGISTER_RW_ACK) {
                err("generic read/write, wrong reply code.");
-               return -EIO;
+               ret = -EIO;
+               goto ret;
        }
-       if (ibuf[3] != 0x0d) {
+       if (st->data[3] != 0x0d) {
                err("generic read/write, wrong length in reply.");
-               return -EIO;
+               ret = -EIO;
+               goto ret;
        }
-       if (ibuf[4] != obuf[4]) {
+       if (st->data[4] != seq) {
                err("generic read/write, wrong sequence in reply.");
-               return -EIO;
+               ret = -EIO;
+               goto ret;
        }
        /*
-          Windows driver doesn't check these fields, in fact sometimes
-          the register in the reply is different that what has been sent
-
-          if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
-          err("generic read/write, wrong register in reply.");
-          return -EIO;
-          }
-          if (ibuf[7] != command) {
-          err("generic read/write wrong command in reply.");
-          return -EIO;
-          }
+        * In thesis, both input and output buffers should have
+        * identical values for st->data[5] to st->data[8].
+        * However, windows driver doesn't check these fields, in fact
+        * sometimes the register in the reply is different that what
+        * has been sent
         */
-       if (ibuf[16] != 0x01) {
+       if (st->data[16] != 0x01) {
                err("generic read/write wrong status code in reply.");
-               return -EIO;
+               ret = -EIO;
+               goto ret;
        }
+
        if (readwrite == AF9005_CMD_READ)
                for (i = 0; i < len; i++)
-                       values[i] = ibuf[8 + i];
+                       values[i] = st->data[8 + i];
 
-       return 0;
+ret:
+       mutex_unlock(&d->data_mutex);
+       return ret;
 
 }
 
@@ -464,8 +464,7 @@ int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
        struct af9005_device_state *st = d->priv;
 
        int ret, i, packet_len;
-       u8 buf[64];
-       u8 ibuf[64];
+       u8 seq;
 
        if (wlen < 0) {
                err("send command, wlen less than 0 bytes. Makes no sense.");
@@ -480,94 +479,97 @@ int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
                return -EINVAL;
        }
        packet_len = wlen + 5;
-       buf[0] = (u8) (packet_len & 0xff);
-       buf[1] = (u8) ((packet_len & 0xff00) >> 8);
-
-       buf[2] = 0x26;          /* packet type */
-       buf[3] = wlen + 3;
-       buf[4] = st->sequence++;
-       buf[5] = command;
-       buf[6] = wlen;
+
+       mutex_lock(&d->data_mutex);
+
+       st->data[0] = (u8) (packet_len & 0xff);
+       st->data[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+       st->data[2] = 0x26;             /* packet type */
+       st->data[3] = wlen + 3;
+       st->data[4] = seq = st->sequence++;
+       st->data[5] = command;
+       st->data[6] = wlen;
        for (i = 0; i < wlen; i++)
-               buf[7 + i] = wbuf[i];
-       ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
-       if (ret)
-               return ret;
-       if (ibuf[2] != 0x27) {
+               st->data[7 + i] = wbuf[i];
+       ret = dvb_usb_generic_rw(d, st->data, wlen + 7, st->data, rlen + 7, 0);
+       if (st->data[2] != 0x27) {
                err("send command, wrong reply code.");
-               return -EIO;
-       }
-       if (ibuf[4] != buf[4]) {
+               ret = -EIO;
+       } else if (st->data[4] != seq) {
                err("send command, wrong sequence in reply.");
-               return -EIO;
-       }
-       if (ibuf[5] != 0x01) {
+               ret = -EIO;
+       } else if (st->data[5] != 0x01) {
                err("send command, wrong status code in reply.");
-               return -EIO;
-       }
-       if (ibuf[6] != rlen) {
+               ret = -EIO;
+       } else if (st->data[6] != rlen) {
                err("send command, invalid data length in reply.");
-               return -EIO;
+               ret = -EIO;
        }
-       for (i = 0; i < rlen; i++)
-               rbuf[i] = ibuf[i + 7];
-       return 0;
+       if (!ret) {
+               for (i = 0; i < rlen; i++)
+                       rbuf[i] = st->data[i + 7];
+       }
+
+       mutex_unlock(&d->data_mutex);
+       return ret;
 }
 
 int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
                       int len)
 {
        struct af9005_device_state *st = d->priv;
-       u8 obuf[16], ibuf[14];
+       u8 seq;
        int ret, i;
 
-       memset(obuf, 0, sizeof(obuf));
-       memset(ibuf, 0, sizeof(ibuf));
+       mutex_lock(&d->data_mutex);
 
-       obuf[0] = 14;           /* length of rest of packet low */
-       obuf[1] = 0;            /* length of rest of packer high */
+       memset(st->data, 0, sizeof(st->data));
 
-       obuf[2] = 0x2a;         /* read/write eeprom */
+       st->data[0] = 14;               /* length of rest of packet low */
+       st->data[1] = 0;                /* length of rest of packer high */
 
-       obuf[3] = 12;           /* size */
+       st->data[2] = 0x2a;             /* read/write eeprom */
 
-       obuf[4] = st->sequence++;
+       st->data[3] = 12;               /* size */
 
-       obuf[5] = 0;            /* read */
+       st->data[4] = seq = st->sequence++;
 
-       obuf[6] = len;
-       obuf[7] = address;
-       ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
-       if (ret)
-               return ret;
-       if (ibuf[2] != 0x2b) {
+       st->data[5] = 0;                /* read */
+
+       st->data[6] = len;
+       st->data[7] = address;
+       ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 14, 0);
+       if (st->data[2] != 0x2b) {
                err("Read eeprom, invalid reply code");
-               return -EIO;
-       }
-       if (ibuf[3] != 10) {
+               ret = -EIO;
+       } else if (st->data[3] != 10) {
                err("Read eeprom, invalid reply length");
-               return -EIO;
-       }
-       if (ibuf[4] != obuf[4]) {
+               ret = -EIO;
+       } else if (st->data[4] != seq) {
                err("Read eeprom, wrong sequence in reply ");
-               return -EIO;
-       }
-       if (ibuf[5] != 1) {
+               ret = -EIO;
+       } else if (st->data[5] != 1) {
                err("Read eeprom, wrong status in reply ");
-               return -EIO;
+               ret = -EIO;
        }
-       for (i = 0; i < len; i++) {
-               values[i] = ibuf[6 + i];
+
+       if (!ret) {
+               for (i = 0; i < len; i++)
+                       values[i] = st->data[6 + i];
        }
-       return 0;
+       mutex_unlock(&d->data_mutex);
+
+       return ret;
 }
 
-static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 *reply,
+                             u8 *buf, int size)
 {
-       u8 buf[FW_BULKOUT_SIZE + 2];
        u16 checksum;
        int act_len, i, ret;
-       memset(buf, 0, sizeof(buf));
+
+       memset(buf, 0, size);
        buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
        buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
        switch (type) {
@@ -720,15 +722,21 @@ static int af9005_download_firmware(struct usb_device *udev, const struct firmwa
 {
        int i, packets, ret, act_len;
 
-       u8 buf[FW_BULKOUT_SIZE + 2];
+       u8 *buf;
        u8 reply;
 
-       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf,
+                                FW_BULKOUT_SIZE + 2);
        if (ret)
-               return ret;
+               goto err;
        if (reply != 0x01) {
                err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
-               return -EIO;
+               ret = -EIO;
+               goto err;
        }
        packets = fw->size / FW_BULKOUT_SIZE;
        buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
@@ -743,28 +751,35 @@ static int af9005_download_firmware(struct usb_device *udev, const struct firmwa
                                   buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
                if (ret) {
                        err("firmware download failed at packet %d with code %d", i, ret);
-                       return ret;
+                       goto err;
                }
        }
-       ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+       ret = af9005_boot_packet(udev, FW_CONFIRM, &reply,
+                                buf, FW_BULKOUT_SIZE + 2);
        if (ret)
-               return ret;
+               goto err;
        if (reply != (u8) (packets & 0xff)) {
                err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
-               return -EIO;
+               ret = -EIO;
+               goto err;
        }
-       ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+       ret = af9005_boot_packet(udev, FW_BOOT, &reply, buf,
+                                FW_BULKOUT_SIZE + 2);
        if (ret)
-               return ret;
-       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+               goto err;
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf,
+                                FW_BULKOUT_SIZE + 2);
        if (ret)
-               return ret;
+               goto err;
        if (reply != 0x02) {
                err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
-               return -EIO;
+               ret = -EIO;
+               goto err;
        }
 
-       return 0;
+err:
+       kfree(buf);
+       return ret;
 
 }
 
@@ -823,53 +838,59 @@ static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
 {
        struct af9005_device_state *st = d->priv;
        int ret, len;
-
-       u8 obuf[5];
-       u8 ibuf[256];
+       u8 seq;
 
        *state = REMOTE_NO_KEY_PRESSED;
        if (rc_decode == NULL) {
                /* it shouldn't never come here */
                return 0;
        }
+
+       mutex_lock(&d->data_mutex);
+
        /* deb_info("rc_query\n"); */
-       obuf[0] = 3;            /* rest of packet length low */
-       obuf[1] = 0;            /* rest of packet lentgh high */
-       obuf[2] = 0x40;         /* read remote */
-       obuf[3] = 1;            /* rest of packet length */
-       obuf[4] = st->sequence++;       /* sequence number */
-       ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+       st->data[0] = 3;                /* rest of packet length low */
+       st->data[1] = 0;                /* rest of packet lentgh high */
+       st->data[2] = 0x40;             /* read remote */
+       st->data[3] = 1;                /* rest of packet length */
+       st->data[4] = seq = st->sequence++;     /* sequence number */
+       ret = dvb_usb_generic_rw(d, st->data, 5, st->data, 256, 0);
        if (ret) {
                err("rc query failed");
-               return ret;
+               goto ret;
        }
-       if (ibuf[2] != 0x41) {
+       if (st->data[2] != 0x41) {
                err("rc query bad header.");
-               return -EIO;
-       }
-       if (ibuf[4] != obuf[4]) {
+               ret = -EIO;
+               goto ret;
+       } else if (st->data[4] != seq) {
                err("rc query bad sequence.");
-               return -EIO;
+               ret = -EIO;
+               goto ret;
        }
-       len = ibuf[5];
+       len = st->data[5];
        if (len > 246) {
                err("rc query invalid length");
-               return -EIO;
+               ret = -EIO;
+               goto ret;
        }
        if (len > 0) {
                deb_rc("rc data (%d) ", len);
-               debug_dump((ibuf + 6), len, deb_rc);
-               ret = rc_decode(d, &ibuf[6], len, event, state);
+               debug_dump((st->data + 6), len, deb_rc);
+               ret = rc_decode(d, &st->data[6], len, event, state);
                if (ret) {
                        err("rc_decode failed");
-                       return ret;
+                       goto ret;
                } else {
                        deb_rc("rc_decode state %x event %x\n", *state, *event);
                        if (*state == REMOTE_KEY_REPEAT)
                                *event = d->last_event;
                }
        }
-       return 0;
+
+ret:
+       mutex_unlock(&d->data_mutex);
+       return ret;
 }
 
 static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
@@ -953,10 +974,16 @@ static int af9005_identify_state(struct usb_device *udev,
                                 int *cold)
 {
        int ret;
-       u8 reply;
-       ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+       u8 reply, *buf;
+
+       buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = af9005_boot_packet(udev, FW_CONFIG, &reply,
+                                buf, FW_BULKOUT_SIZE + 2);
        if (ret)
-               return ret;
+               goto err;
        deb_info("result of FW_CONFIG in identify state %d\n", reply);
        if (reply == 0x01)
                *cold = 1;
@@ -965,7 +992,10 @@ static int af9005_identify_state(struct usb_device *udev,
        else
                return -EIO;
        deb_info("Identify state cold = %d\n", *cold);
-       return 0;
+
+err:
+       kfree(buf);
+       return ret;
 }
 
 static struct dvb_usb_device_properties af9005_properties;
@@ -974,7 +1004,7 @@ static int af9005_usb_probe(struct usb_interface *intf,
                            const struct usb_device_id *id)
 {
        return dvb_usb_device_init(intf, &af9005_properties,
-                                  THIS_MODULE, NULL, adapter_nr);
+                                 THIS_MODULE, NULL, adapter_nr);
 }
 
 enum af9005_usb_table_entry {
index 9fd1527494ebd65ab200c38f13a20e28330034a1..290275bc7fdee038be993754f9f103c2e22cef36 100644 (file)
@@ -41,6 +41,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 struct cinergyt2_state {
        u8 rc_counter;
+       unsigned char data[64];
 };
 
 /* We are missing a release hook with usb_device data */
@@ -50,38 +51,57 @@ static struct dvb_usb_device_properties cinergyt2_properties;
 
 static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
 {
-       char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
-       char result[64];
-       return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
-                               sizeof(result), 0);
+       struct dvb_usb_device *d = adap->dev;
+       struct cinergyt2_state *st = d->priv;
+       int ret;
+
+       mutex_lock(&d->data_mutex);
+       st->data[0] = CINERGYT2_EP1_CONTROL_STREAM_TRANSFER;
+       st->data[1] = enable ? 1 : 0;
+
+       ret = dvb_usb_generic_rw(d, st->data, 2, st->data, 64, 0);
+       mutex_unlock(&d->data_mutex);
+
+       return ret;
 }
 
 static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
 {
-       char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
-       char state[3];
-       return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
+       struct cinergyt2_state *st = d->priv;
+       int ret;
+
+       mutex_lock(&d->data_mutex);
+       st->data[0] = CINERGYT2_EP1_SLEEP_MODE;
+       st->data[1] = enable ? 0 : 1;
+
+       ret = dvb_usb_generic_rw(d, st->data, 2, st->data, 3, 0);
+       mutex_unlock(&d->data_mutex);
+
+       return ret;
 }
 
 static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
-       char state[3];
+       struct dvb_usb_device *d = adap->dev;
+       struct cinergyt2_state *st = d->priv;
        int ret;
 
        adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev);
 
-       ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
-                               sizeof(state), 0);
+       mutex_lock(&d->data_mutex);
+       st->data[0] = CINERGYT2_EP1_GET_FIRMWARE_VERSION;
+
+       ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 3, 0);
        if (ret < 0) {
                deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
                        "state info\n");
        }
+       mutex_unlock(&d->data_mutex);
 
        /* Copy this pointer as we are gonna need it in the release phase */
        cinergyt2_usb_device = adap->dev;
 
-       return 0;
+       return ret;
 }
 
 static struct rc_map_table rc_map_cinergyt2_table[] = {
@@ -141,13 +161,18 @@ static int repeatable_keys[] = {
 static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
        struct cinergyt2_state *st = d->priv;
-       u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
-       int i;
+       int i, ret;
 
        *state = REMOTE_NO_KEY_PRESSED;
 
-       dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
-       if (key[4] == 0xff) {
+       mutex_lock(&d->data_mutex);
+       st->data[0] = CINERGYT2_EP1_GET_RC_EVENTS;
+
+       ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 5, 0);
+       if (ret < 0)
+               goto ret;
+
+       if (st->data[4] == 0xff) {
                /* key repeat */
                st->rc_counter++;
                if (st->rc_counter > RC_REPEAT_DELAY) {
@@ -157,34 +182,36 @@ static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                                        *event = d->last_event;
                                        deb_rc("repeat key, event %x\n",
                                                   *event);
-                                       return 0;
+                                       goto ret;
                                }
                        }
                        deb_rc("repeated key (non repeatable)\n");
                }
-               return 0;
+               goto ret;
        }
 
        /* hack to pass checksum on the custom field */
-       key[2] = ~key[1];
-       dvb_usb_nec_rc_key_to_event(d, key, event, state);
-       if (key[0] != 0) {
+       st->data[2] = ~st->data[1];
+       dvb_usb_nec_rc_key_to_event(d, st->data, event, state);
+       if (st->data[0] != 0) {
                if (*event != d->last_event)
                        st->rc_counter = 0;
 
-               deb_rc("key: %*ph\n", 5, key);
+               deb_rc("key: %*ph\n", 5, st->data);
        }
-       return 0;
+
+ret:
+       mutex_unlock(&d->data_mutex);
+       return ret;
 }
 
 static int cinergyt2_usb_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
        return dvb_usb_device_init(intf, &cinergyt2_properties,
-                                       THIS_MODULE, NULL, adapter_nr);
+                                  THIS_MODULE, NULL, adapter_nr);
 }
 
-
 static struct usb_device_id cinergyt2_usb_table[] = {
        { USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
        { 0 }
index b3ec743a7a2e6816eafa6d8f20a128eaabead3c4..2d29b4174dba0e94977aa988e6a309704898af6d 100644 (file)
@@ -139,32 +139,42 @@ static uint16_t compute_tps(struct dtv_frontend_properties *op)
 struct cinergyt2_fe_state {
        struct dvb_frontend fe;
        struct dvb_usb_device *d;
+
+       unsigned char data[64];
+       struct mutex data_mutex;
+
+       struct dvbt_get_status_msg status;
 };
 
 static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
                                    enum fe_status *status)
 {
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
-       struct dvbt_get_status_msg result;
-       u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
        int ret;
 
-       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
-                       sizeof(result), 0);
+       mutex_lock(&state->data_mutex);
+       state->data[0] = CINERGYT2_EP1_GET_TUNER_STATUS;
+
+       ret = dvb_usb_generic_rw(state->d, state->data, 1,
+                                state->data, sizeof(state->status), 0);
+       if (!ret)
+               memcpy(&state->status, state->data, sizeof(state->status));
+       mutex_unlock(&state->data_mutex);
+
        if (ret < 0)
                return ret;
 
        *status = 0;
 
-       if (0xffff - le16_to_cpu(result.gain) > 30)
+       if (0xffff - le16_to_cpu(state->status.gain) > 30)
                *status |= FE_HAS_SIGNAL;
-       if (result.lock_bits & (1 << 6))
+       if (state->status.lock_bits & (1 << 6))
                *status |= FE_HAS_LOCK;
-       if (result.lock_bits & (1 << 5))
+       if (state->status.lock_bits & (1 << 5))
                *status |= FE_HAS_SYNC;
-       if (result.lock_bits & (1 << 4))
+       if (state->status.lock_bits & (1 << 4))
                *status |= FE_HAS_CARRIER;
-       if (result.lock_bits & (1 << 1))
+       if (state->status.lock_bits & (1 << 1))
                *status |= FE_HAS_VITERBI;
 
        if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
@@ -177,34 +187,16 @@ static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
 static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
-       struct dvbt_get_status_msg status;
-       char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-       int ret;
-
-       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
-                               sizeof(status), 0);
-       if (ret < 0)
-               return ret;
 
-       *ber = le32_to_cpu(status.viterbi_error_rate);
+       *ber = le32_to_cpu(state->status.viterbi_error_rate);
        return 0;
 }
 
 static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
 {
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
-       struct dvbt_get_status_msg status;
-       u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-       int ret;
 
-       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
-                               sizeof(status), 0);
-       if (ret < 0) {
-               err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
-                       ret);
-               return ret;
-       }
-       *unc = le32_to_cpu(status.uncorrected_block_count);
+       *unc = le32_to_cpu(state->status.uncorrected_block_count);
        return 0;
 }
 
@@ -212,35 +204,16 @@ static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
                                                u16 *strength)
 {
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
-       struct dvbt_get_status_msg status;
-       char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-       int ret;
 
-       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
-                               sizeof(status), 0);
-       if (ret < 0) {
-               err("cinergyt2_fe_read_signal_strength() Failed!"
-                       " (Error=%d)\n", ret);
-               return ret;
-       }
-       *strength = (0xffff - le16_to_cpu(status.gain));
+       *strength = (0xffff - le16_to_cpu(state->status.gain));
        return 0;
 }
 
 static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
-       struct dvbt_get_status_msg status;
-       char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-       int ret;
 
-       ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
-                               sizeof(status), 0);
-       if (ret < 0) {
-               err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
-               return ret;
-       }
-       *snr = (status.snr << 8) | status.snr;
+       *snr = (state->status.snr << 8) | state->status.snr;
        return 0;
 }
 
@@ -266,34 +239,36 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
-       struct dvbt_set_parameters_msg param;
-       char result[2];
+       struct dvbt_set_parameters_msg *param;
        int err;
 
-       param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-       param.tps = cpu_to_le16(compute_tps(fep));
-       param.freq = cpu_to_le32(fep->frequency / 1000);
-       param.flags = 0;
+       mutex_lock(&state->data_mutex);
+
+       param = (void *)state->data;
+       param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
+       param->tps = cpu_to_le16(compute_tps(fep));
+       param->freq = cpu_to_le32(fep->frequency / 1000);
+       param->flags = 0;
 
        switch (fep->bandwidth_hz) {
        default:
        case 8000000:
-               param.bandwidth = 8;
+               param->bandwidth = 8;
                break;
        case 7000000:
-               param.bandwidth = 7;
+               param->bandwidth = 7;
                break;
        case 6000000:
-               param.bandwidth = 6;
+               param->bandwidth = 6;
                break;
        }
 
-       err = dvb_usb_generic_rw(state->d,
-                       (char *)&param, sizeof(param),
-                       result, sizeof(result), 0);
+       err = dvb_usb_generic_rw(state->d, state->data, sizeof(*param),
+                                state->data, 2, 0);
        if (err < 0)
                err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
 
+       mutex_unlock(&state->data_mutex);
        return (err < 0) ? err : 0;
 }
 
@@ -315,6 +290,7 @@ struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
        s->d = d;
        memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
        s->fe.demodulator_priv = s;
+       mutex_init(&s->data_mutex);
        return &s->fe;
 }
 
index 907ac01ae2979a56657e6ddc32fafecfbb9c9042..243403081fa53f2860a5b67469593b5ecffae62a 100644 (file)
@@ -45,9 +45,6 @@
 #include "si2168.h"
 #include "si2157.h"
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  80
-
 /* debug */
 static int dvb_usb_cxusb_debug;
 module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
@@ -61,23 +58,27 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
                          u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 {
-       int wo = (rbuf == NULL || rlen == 0); /* write-only */
-       u8 sndbuf[MAX_XFER_SIZE];
+       struct cxusb_state *st = d->priv;
+       int ret, wo;
 
-       if (1 + wlen > sizeof(sndbuf)) {
-               warn("i2c wr: len=%d is too big!\n",
-                    wlen);
+       if (1 + wlen > MAX_XFER_SIZE) {
+               warn("i2c wr: len=%d is too big!\n", wlen);
                return -EOPNOTSUPP;
        }
 
-       memset(sndbuf, 0, 1+wlen);
+       wo = (rbuf == NULL || rlen == 0); /* write-only */
 
-       sndbuf[0] = cmd;
-       memcpy(&sndbuf[1], wbuf, wlen);
+       mutex_lock(&d->data_mutex);
+       st->data[0] = cmd;
+       memcpy(&st->data[1], wbuf, wlen);
        if (wo)
-               return dvb_usb_generic_write(d, sndbuf, 1+wlen);
+               ret = dvb_usb_generic_write(d, st->data, 1 + wlen);
        else
-               return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
+               ret = dvb_usb_generic_rw(d, st->data, 1 + wlen,
+                                        rbuf, rlen, 0);
+
+       mutex_unlock(&d->data_mutex);
+       return ret;
 }
 
 /* GPIO */
index 527ff7905e1590961b64b8edd3b62b859a9f903a..18acda19527a644fc31e0596e7206c70193cf1d0 100644 (file)
 #define CMD_ANALOG        0x50
 #define CMD_DIGITAL       0x51
 
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE  80
+
 struct cxusb_state {
        u8 gpio_write_state[3];
        struct i2c_client *i2c_client_demod;
        struct i2c_client *i2c_client_tuner;
+
+       unsigned char data[MAX_XFER_SIZE];
 };
 
 #endif
index f3196658fb700706e12b61fd8b0951d25c2f1152..47ce9d5de4c678e78d1cd6cc075661ddaf40b0f6 100644 (file)
@@ -213,7 +213,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                                 usb_rcvctrlpipe(d->udev, 0),
                                                 REQUEST_NEW_I2C_READ,
                                                 USB_TYPE_VENDOR | USB_DIR_IN,
-                                                value, index, msg[i].buf,
+                                                value, index, st->buf,
                                                 msg[i].len,
                                                 USB_CTRL_GET_TIMEOUT);
                        if (result < 0) {
@@ -221,6 +221,14 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                break;
                        }
 
+                       if (msg[i].len > sizeof(st->buf)) {
+                               deb_info("buffer too small to fit %d bytes\n",
+                                        msg[i].len);
+                               return -EIO;
+                       }
+
+                       memcpy(msg[i].buf, st->buf, msg[i].len);
+
                        deb_data("<<< ");
                        debug_dump(msg[i].buf, msg[i].len, deb_data);
 
@@ -238,6 +246,13 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                        /* I2C ctrl + FE bus; */
                        st->buf[3] = ((gen_mode << 6) & 0xC0) |
                                 ((bus_mode << 4) & 0x30);
+
+                       if (msg[i].len > sizeof(st->buf) - 4) {
+                               deb_info("i2c message to big: %d\n",
+                                        msg[i].len);
+                               return -EIO;
+                       }
+
                        /* The Actual i2c payload */
                        memcpy(&st->buf[4], msg[i].buf, msg[i].len);
 
@@ -283,6 +298,11 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
                /* fill in the address */
                st->buf[1] = msg[i].addr << 1;
                /* fill the buffer */
+               if (msg[i].len > sizeof(st->buf) - 2) {
+                       deb_info("i2c xfer to big: %d\n",
+                               msg[i].len);
+                       return -EIO;
+               }
                memcpy(&st->buf[2], msg[i].buf, msg[i].len);
 
                /* write/read request */
@@ -292,13 +312,20 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
 
                        /* special thing in the current firmware: when length is zero the read-failed */
                        len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
-                                       msg[i+1].buf, msg[i+1].len);
+                                             st->buf, msg[i + 1].len);
                        if (len <= 0) {
                                deb_info("I2C read failed on address 0x%02x\n",
                                                msg[i].addr);
                                break;
                        }
 
+                       if (msg[i + 1].len > sizeof(st->buf)) {
+                               deb_info("i2c xfer buffer to small for %d\n",
+                                       msg[i].len);
+                               return -EIO;
+                       }
+                       memcpy(msg[i + 1].buf, st->buf, msg[i + 1].len);
+
                        msg[i+1].len = len;
 
                        i++;
@@ -677,7 +704,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
        struct dvb_usb_device *d = purb->context;
        struct dib0700_rc_response *poll_reply;
        enum rc_type protocol;
-       u32 uninitialized_var(keycode);
+       u32 keycode;
        u8 toggle;
 
        deb_info("%s()\n", __func__);
@@ -718,7 +745,8 @@ static void dib0700_rc_urb_completion(struct urb *purb)
                    poll_reply->nec.data       == 0x00 &&
                    poll_reply->nec.not_data   == 0xff) {
                        poll_reply->data_state = 2;
-                       break;
+                       rc_repeat(d->rc_dev);
+                       goto resubmit;
                }
 
                if ((poll_reply->nec.data ^ poll_reply->nec.not_data) != 0xff) {
index 0857b56e652cf96515d34b890ff65693c5936507..ef1b8ee75c577f00c61b07b80859ef063722d907 100644 (file)
@@ -508,8 +508,6 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
 
 #define DEFAULT_RC_INTERVAL 50
 
-static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
-
 /*
  * This function is used only when firmware is < 1.20 version. Newer
  * firmwares use bulk mode, with functions implemented at dib0700_core,
@@ -517,7 +515,6 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
  */
 static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
 {
-       u8 key[4];
        enum rc_type protocol;
        u32 scancode;
        u8 toggle;
@@ -532,39 +529,43 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
                return 0;
        }
 
-       i = dib0700_ctrl_rd(d, rc_request, 2, key, 4);
+       st->buf[0] = REQUEST_POLL_RC;
+       st->buf[1] = 0;
+
+       i = dib0700_ctrl_rd(d, st->buf, 2, st->buf, 4);
        if (i <= 0) {
                err("RC Query Failed");
-               return -1;
+               return -EIO;
        }
 
        /* losing half of KEY_0 events from Philipps rc5 remotes.. */
-       if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0)
+       if (st->buf[0] == 0 && st->buf[1] == 0
+           && st->buf[2] == 0 && st->buf[3] == 0)
                return 0;
 
-       /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]);  */
+       /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)st->buf[3 - 2],(int)st->buf[3 - 3],(int)st->buf[3 - 1],(int)st->buf[3]);  */
 
        dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */
 
        switch (d->props.rc.core.protocol) {
        case RC_BIT_NEC:
                /* NEC protocol sends repeat code as 0 0 0 FF */
-               if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
-                   (key[3] == 0xff)) {
+               if ((st->buf[3 - 2] == 0x00) && (st->buf[3 - 3] == 0x00) &&
+                   (st->buf[3] == 0xff)) {
                        rc_repeat(d->rc_dev);
                        return 0;
                }
 
                protocol = RC_TYPE_NEC;
-               scancode = RC_SCANCODE_NEC(key[3-2], key[3-3]);
+               scancode = RC_SCANCODE_NEC(st->buf[3 - 2], st->buf[3 - 3]);
                toggle = 0;
                break;
 
        default:
                /* RC-5 protocol changes toggle bit on new keypress */
                protocol = RC_TYPE_RC5;
-               scancode = RC_SCANCODE_RC5(key[3-2], key[3-3]);
-               toggle = key[3-1];
+               scancode = RC_SCANCODE_RC5(st->buf[3 - 2], st->buf[3 - 3]);
+               toggle = st->buf[3 - 1];
                break;
        }
 
index 18ed3bfbb5e2a95f5127b41d0e1f15cce01b1f07..de3ee2547479428cd1c14347db5332ea1090c60d 100644 (file)
@@ -62,72 +62,117 @@ EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
 
 int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
-       u8 b[3];
+       u8 *b;
        int ret;
+
+       b = kmalloc(3, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+
        b[0] = DIBUSB_REQ_SET_IOCTL;
        b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
        b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
-       ret = dvb_usb_generic_write(d,b,3);
+
+       ret = dvb_usb_generic_write(d, b, 3);
+
+       kfree(b);
+
        msleep(10);
+
        return ret;
 }
 EXPORT_SYMBOL(dibusb_power_ctrl);
 
 int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
-       u8 b[3] = { 0 };
        int ret;
+       u8 *b;
+
+       b = kmalloc(3, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
 
        if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
-               return ret;
+               goto ret;
 
        if (onoff) {
                b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
                b[1] = 0x00;
-               if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
-                       return ret;
+               ret = dvb_usb_generic_write(adap->dev, b, 2);
+               if (ret  < 0)
+                       goto ret;
        }
 
        b[0] = DIBUSB_REQ_SET_IOCTL;
        b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
-       return dvb_usb_generic_write(adap->dev,b,3);
+       ret = dvb_usb_generic_write(adap->dev, b, 3);
+
+ret:
+       kfree(b);
+       return ret;
 }
 EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
 
 int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
-       if (onoff) {
-               u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
-               return dvb_usb_generic_write(d,b,3);
-       } else
+       u8 *b;
+       int ret;
+
+       if (!onoff)
                return 0;
+
+       b = kmalloc(3, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+
+       b[0] = DIBUSB_REQ_SET_IOCTL;
+       b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
+       b[2] = DIBUSB_IOCTL_POWER_WAKEUP;
+
+       ret = dvb_usb_generic_write(d, b, 3);
+
+       kfree(b);
+
+       return ret;
 }
 EXPORT_SYMBOL(dibusb2_0_power_ctrl);
 
 static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
                          u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
-       u8 sndbuf[MAX_XFER_SIZE]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
+       u8 *sndbuf;
+       int ret, wo, len;
+
        /* write only ? */
-       int wo = (rbuf == NULL || rlen == 0),
-               len = 2 + wlen + (wo ? 0 : 2);
+       wo = (rbuf == NULL || rlen == 0);
+
+       len = 2 + wlen + (wo ? 0 : 2);
+
+       sndbuf = kmalloc(MAX_XFER_SIZE, GFP_KERNEL);
+       if (!sndbuf)
+               return -ENOMEM;
 
-       if (4 + wlen > sizeof(sndbuf)) {
+       if (4 + wlen > MAX_XFER_SIZE) {
                warn("i2c wr: len=%d is too big!\n", wlen);
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               goto ret;
        }
 
        sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
        sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
 
-       memcpy(&sndbuf[2],wbuf,wlen);
+       memcpy(&sndbuf[2], wbuf, wlen);
 
        if (!wo) {
-               sndbuf[wlen+2] = (rlen >> 8) & 0xff;
-               sndbuf[wlen+3] = rlen & 0xff;
+               sndbuf[wlen + 2] = (rlen >> 8) & 0xff;
+               sndbuf[wlen + 3] = rlen & 0xff;
        }
 
-       return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
+       ret = dvb_usb_generic_rw(d, sndbuf, len, rbuf, rlen, 0);
+
+ret:
+       kfree(sndbuf);
+       return ret;
 }
 
 /*
@@ -319,11 +364,27 @@ EXPORT_SYMBOL(rc_map_dibusb_table);
 
 int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
-       dvb_usb_generic_rw(d,&cmd,1,key,5,0);
-       dvb_usb_nec_rc_key_to_event(d,key,event,state);
-       if (key[0] != 0)
-               deb_info("key: %*ph\n", 5, key);
-       return 0;
+       u8 *buf;
+       int ret;
+
+       buf = kmalloc(5, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = DIBUSB_REQ_POLL_REMOTE;
+
+       ret = dvb_usb_generic_rw(d, buf, 1, buf, 5, 0);
+       if (ret < 0)
+               goto ret;
+
+       dvb_usb_nec_rc_key_to_event(d, buf, event, state);
+
+       if (buf[0] != 0)
+               deb_info("key: %*ph\n", 5, buf);
+
+       kfree(buf);
+
+ret:
+       return ret;
 }
 EXPORT_SYMBOL(dibusb_rc_query);
index 3f82163d8ab89061410bdff4b68bea2e1d153c27..697be2a17adef131b68a2f34a2401b2108174b68 100644 (file)
@@ -96,6 +96,9 @@
 #define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
 #define DIBUSB_IOCTL_CMD_DISABLE_STREAM        0x02
 
+/* Max transfer size done by I2C transfer functions */
+#define MAX_XFER_SIZE  64
+
 struct dibusb_state {
        struct dib_fe_xfer_ops ops;
        int mt2060_present;
index 63134335c99406ca7df3d284cd3ba95d4154cae3..4284f6984dc1ffe14698b6fcdc42aad8cf69bf32 100644 (file)
@@ -28,22 +28,26 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 static int digitv_ctrl_msg(struct dvb_usb_device *d,
                u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 {
-       int wo = (rbuf == NULL || rlen == 0); /* write-only */
-       u8 sndbuf[7],rcvbuf[7];
-       memset(sndbuf,0,7); memset(rcvbuf,0,7);
+       struct digitv_state *st = d->priv;
+       int ret, wo;
 
-       sndbuf[0] = cmd;
-       sndbuf[1] = vv;
-       sndbuf[2] = wo ? wlen : rlen;
+       wo = (rbuf == NULL || rlen == 0); /* write-only */
+
+       memset(st->sndbuf, 0, 7);
+       memset(st->rcvbuf, 0, 7);
+
+       st->sndbuf[0] = cmd;
+       st->sndbuf[1] = vv;
+       st->sndbuf[2] = wo ? wlen : rlen;
 
        if (wo) {
-               memcpy(&sndbuf[3],wbuf,wlen);
-               dvb_usb_generic_write(d,sndbuf,7);
+               memcpy(&st->sndbuf[3], wbuf, wlen);
+               ret = dvb_usb_generic_write(d, st->sndbuf, 7);
        } else {
-               dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
-               memcpy(rbuf,&rcvbuf[3],rlen);
+               ret = dvb_usb_generic_rw(d, st->sndbuf, 7, st->rcvbuf, 7, 10);
+               memcpy(rbuf, &st->rcvbuf[3], rlen);
        }
-       return 0;
+       return ret;
 }
 
 /* I2C */
index 908c09f4966b89b8923569b35a5a2cbc3b8a6727..581e09c25491bfe54a683fbfd094a890c0351c4a 100644 (file)
@@ -5,7 +5,10 @@
 #include "dvb-usb.h"
 
 struct digitv_state {
-    int is_nxt6000;
+       int is_nxt6000;
+
+       unsigned char sndbuf[7];
+       unsigned char rcvbuf[7];
 };
 
 /* protocol (from usblogging and the SDK:
index c09332bd99cb7c5e41699e2a9d435c3072432277..f5c042baa254e0cf3be54eb759918161f82202b1 100644 (file)
@@ -18,17 +18,28 @@ struct dtt200u_fe_state {
 
        struct dtv_frontend_properties fep;
        struct dvb_frontend frontend;
+
+       unsigned char data[80];
+       struct mutex data_mutex;
 };
 
 static int dtt200u_fe_read_status(struct dvb_frontend *fe,
                                  enum fe_status *stat)
 {
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 st = GET_TUNE_STATUS, b[3];
+       int ret;
+
+       mutex_lock(&state->data_mutex);
+       state->data[0] = GET_TUNE_STATUS;
 
-       dvb_usb_generic_rw(state->d,&st,1,b,3,0);
+       ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 3, 0);
+       if (ret < 0) {
+               *stat = 0;
+               mutex_unlock(&state->data_mutex);
+               return ret;
+       }
 
-       switch (b[0]) {
+       switch (state->data[0]) {
                case 0x01:
                        *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
                                FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
@@ -41,51 +52,86 @@ static int dtt200u_fe_read_status(struct dvb_frontend *fe,
                        *stat = 0;
                        break;
        }
+       mutex_unlock(&state->data_mutex);
        return 0;
 }
 
 static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
 {
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw = GET_VIT_ERR_CNT,b[3];
-       dvb_usb_generic_rw(state->d,&bw,1,b,3,0);
-       *ber = (b[0] << 16) | (b[1] << 8) | b[2];
-       return 0;
+       int ret;
+
+       mutex_lock(&state->data_mutex);
+       state->data[0] = GET_VIT_ERR_CNT;
+
+       ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 3, 0);
+       if (ret >= 0)
+               *ber = (state->data[0] << 16) | (state->data[1] << 8) | state->data[2];
+
+       mutex_unlock(&state->data_mutex);
+       return ret;
 }
 
 static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 {
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw = GET_RS_UNCOR_BLK_CNT,b[2];
+       int ret;
 
-       dvb_usb_generic_rw(state->d,&bw,1,b,2,0);
-       *unc = (b[0] << 8) | b[1];
-       return 0;
+       mutex_lock(&state->data_mutex);
+       state->data[0] = GET_RS_UNCOR_BLK_CNT;
+
+       ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 2, 0);
+       if (ret >= 0)
+               *unc = (state->data[0] << 8) | state->data[1];
+
+       mutex_unlock(&state->data_mutex);
+       return ret;
 }
 
 static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 {
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw = GET_AGC, b;
-       dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
-       *strength = (b << 8) | b;
-       return 0;
+       int ret;
+
+       mutex_lock(&state->data_mutex);
+       state->data[0] = GET_AGC;
+
+       ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 1, 0);
+       if (ret >= 0)
+               *strength = (state->data[0] << 8) | state->data[0];
+
+       mutex_unlock(&state->data_mutex);
+       return ret;
 }
 
 static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 bw = GET_SNR,br;
-       dvb_usb_generic_rw(state->d,&bw,1,&br,1,0);
-       *snr = ~((br << 8) | br);
-       return 0;
+       int ret;
+
+       mutex_lock(&state->data_mutex);
+       state->data[0] = GET_SNR;
+
+       ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 1, 0);
+       if (ret >= 0)
+               *snr = ~((state->data[0] << 8) | state->data[0]);
+
+       mutex_unlock(&state->data_mutex);
+       return ret;
 }
 
 static int dtt200u_fe_init(struct dvb_frontend* fe)
 {
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       u8 b = SET_INIT;
-       return dvb_usb_generic_write(state->d,&b,1);
+       int ret;
+
+       mutex_lock(&state->data_mutex);
+       state->data[0] = SET_INIT;
+
+       ret = dvb_usb_generic_write(state->d, state->data, 1);
+       mutex_unlock(&state->data_mutex);
+
+       return ret;
 }
 
 static int dtt200u_fe_sleep(struct dvb_frontend* fe)
@@ -105,39 +151,40 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       int i;
-       enum fe_status st;
+       int ret;
        u16 freq = fep->frequency / 250000;
-       u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
 
+       mutex_lock(&state->data_mutex);
+       state->data[0] = SET_BANDWIDTH;
        switch (fep->bandwidth_hz) {
        case 8000000:
-               bwbuf[1] = 8;
+               state->data[1] = 8;
                break;
        case 7000000:
-               bwbuf[1] = 7;
+               state->data[1] = 7;
                break;
        case 6000000:
-               bwbuf[1] = 6;
+               state->data[1] = 6;
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto ret;
        }
 
-       dvb_usb_generic_write(state->d,bwbuf,2);
+       ret = dvb_usb_generic_write(state->d, state->data, 2);
+       if (ret < 0)
+               goto ret;
 
-       freqbuf[1] = freq & 0xff;
-       freqbuf[2] = (freq >> 8) & 0xff;
-       dvb_usb_generic_write(state->d,freqbuf,3);
+       state->data[0] = SET_RF_FREQ;
+       state->data[1] = freq & 0xff;
+       state->data[2] = (freq >> 8) & 0xff;
+       ret = dvb_usb_generic_write(state->d, state->data, 3);
+       if (ret < 0)
+               goto ret;
 
-       for (i = 0; i < 30; i++) {
-               msleep(20);
-               dtt200u_fe_read_status(fe, &st);
-               if (st & FE_TIMEDOUT)
-                       continue;
-       }
-
-       return 0;
+ret:
+       mutex_unlock(&state->data_mutex);
+       return ret;
 }
 
 static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
@@ -169,6 +216,7 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
        deb_info("attaching frontend dtt200u\n");
 
        state->d = d;
+       mutex_init(&state->data_mutex);
 
        memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
index d2a01b50af0daf7ce7ab7d17686b845574c291a1..fcbff7fb0c4e192b9409b23bc10e7e1c66222d44 100644 (file)
@@ -20,75 +20,115 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
+struct dtt200u_state {
+       unsigned char data[80];
+};
+
 static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
-       u8 b = SET_INIT;
+       struct dtt200u_state *st = d->priv;
+       int ret = 0;
+
+       mutex_lock(&d->data_mutex);
+
+       st->data[0] = SET_INIT;
 
        if (onoff)
-               dvb_usb_generic_write(d,&b,2);
+               ret = dvb_usb_generic_write(d, st->data, 2);
 
-       return 0;
+       mutex_unlock(&d->data_mutex);
+       return ret;
 }
 
 static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
-       u8 b_streaming[2] = { SET_STREAMING, onoff };
-       u8 b_rst_pid = RESET_PID_FILTER;
+       struct dvb_usb_device *d = adap->dev;
+       struct dtt200u_state *st = d->priv;
+       int ret;
 
-       dvb_usb_generic_write(adap->dev, b_streaming, 2);
+       mutex_lock(&d->data_mutex);
+       st->data[0] = SET_STREAMING;
+       st->data[1] = onoff;
 
-       if (onoff == 0)
-               dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
-       return 0;
+       ret = dvb_usb_generic_write(adap->dev, st->data, 2);
+       if (ret < 0)
+               goto ret;
+
+       if (onoff)
+               goto ret;
+
+       st->data[0] = RESET_PID_FILTER;
+       ret = dvb_usb_generic_write(adap->dev, st->data, 1);
+
+ret:
+       mutex_unlock(&d->data_mutex);
+
+       return ret;
 }
 
 static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
 {
-       u8 b_pid[4];
+       struct dvb_usb_device *d = adap->dev;
+       struct dtt200u_state *st = d->priv;
+       int ret;
+
        pid = onoff ? pid : 0;
 
-       b_pid[0] = SET_PID_FILTER;
-       b_pid[1] = index;
-       b_pid[2] = pid & 0xff;
-       b_pid[3] = (pid >> 8) & 0x1f;
+       mutex_lock(&d->data_mutex);
+       st->data[0] = SET_PID_FILTER;
+       st->data[1] = index;
+       st->data[2] = pid & 0xff;
+       st->data[3] = (pid >> 8) & 0x1f;
+
+       ret = dvb_usb_generic_write(adap->dev, st->data, 4);
+       mutex_unlock(&d->data_mutex);
 
-       return dvb_usb_generic_write(adap->dev, b_pid, 4);
+       return ret;
 }
 
 static int dtt200u_rc_query(struct dvb_usb_device *d)
 {
-       u8 key[5],cmd = GET_RC_CODE;
+       struct dtt200u_state *st = d->priv;
        u32 scancode;
+       int ret;
+
+       mutex_lock(&d->data_mutex);
+       st->data[0] = GET_RC_CODE;
 
-       dvb_usb_generic_rw(d,&cmd,1,key,5,0);
-       if (key[0] == 1) {
+       ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 5, 0);
+       if (ret < 0)
+               goto ret;
+
+       if (st->data[0] == 1) {
                enum rc_type proto = RC_TYPE_NEC;
 
-               scancode = key[1];
-               if ((u8) ~key[1] != key[2]) {
+               scancode = st->data[1];
+               if ((u8) ~st->data[1] != st->data[2]) {
                        /* Extended NEC */
                        scancode = scancode << 8;
-                       scancode |= key[2];
+                       scancode |= st->data[2];
                        proto = RC_TYPE_NECX;
                }
                scancode = scancode << 8;
-               scancode |= key[3];
+               scancode |= st->data[3];
 
                /* Check command checksum is ok */
-               if ((u8) ~key[3] == key[4])
+               if ((u8) ~st->data[3] == st->data[4])
                        rc_keydown(d->rc_dev, proto, scancode, 0);
                else
                        rc_keyup(d->rc_dev);
-       } else if (key[0] == 2) {
+       } else if (st->data[0] == 2) {
                rc_repeat(d->rc_dev);
        } else {
                rc_keyup(d->rc_dev);
        }
 
-       if (key[0] != 0)
-               deb_info("key: %*ph\n", 5, key);
+       if (st->data[0] != 0)
+               deb_info("st->data: %*ph\n", 5, st->data);
 
-       return 0;
+ret:
+       mutex_unlock(&d->data_mutex);
+       return ret;
 }
 
 static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
@@ -140,6 +180,8 @@ static struct dvb_usb_device_properties dtt200u_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-dtt200u-01.fw",
 
+       .size_of_priv     = sizeof(struct dtt200u_state),
+
        .num_adapters = 1,
        .adapter = {
                {
@@ -190,6 +232,8 @@ static struct dvb_usb_device_properties wt220u_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-wt220u-02.fw",
 
+       .size_of_priv     = sizeof(struct dtt200u_state),
+
        .num_adapters = 1,
        .adapter = {
                {
@@ -240,6 +284,8 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-wt220u-fc03.fw",
 
+       .size_of_priv     = sizeof(struct dtt200u_state),
+
        .num_adapters = 1,
        .adapter = {
                {
@@ -290,6 +336,8 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-wt220u-zl0353-01.fw",
 
+       .size_of_priv     = sizeof(struct dtt200u_state),
+
        .num_adapters = 1,
        .adapter = {
                {
@@ -340,6 +388,8 @@ static struct dvb_usb_device_properties wt220u_miglia_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-wt220u-miglia-01.fw",
 
+       .size_of_priv     = sizeof(struct dtt200u_state),
+
        .num_adapters = 1,
        .generic_bulk_ctrl_endpoint = 0x01,
 
index 3d11df41cac0300c00a5d635412b233d232d338f..c60fb54f445f582357ca949b3e4f6775e0822e12 100644 (file)
@@ -31,9 +31,14 @@ module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
+struct dtv5100_state {
+       unsigned char data[80];
+};
+
 static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
                           u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
+       struct dtv5100_state *st = d->priv;
        u8 request;
        u8 type;
        u16 value;
@@ -60,9 +65,10 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
        }
        index = (addr << 8) + wbuf[0];
 
+       memcpy(st->data, rbuf, rlen);
        msleep(1); /* avoid I2C errors */
        return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
-                              type, value, index, rbuf, rlen,
+                              type, value, index, st->data, rlen,
                               DTV5100_USB_TIMEOUT);
 }
 
@@ -176,7 +182,7 @@ static struct dvb_usb_device_properties dtv5100_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
 
-       .size_of_priv = 0,
+       .size_of_priv = sizeof(struct dtv5100_state),
 
        .num_adapters = 1,
        .adapter = {{
index 3896ba9a4179670687eadb63bdd199e251dc904e..84308569e7dc12a7911304fc4c8c2abb72b49082 100644 (file)
@@ -142,6 +142,7 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
 {
        int ret = 0;
 
+       mutex_init(&d->data_mutex);
        mutex_init(&d->usb_mutex);
        mutex_init(&d->i2c_mutex);
 
index 639c4678c65b96c82293f7546919768401f43dbd..107255b08b2b1f5c5454286938319d63b48208a9 100644 (file)
@@ -404,8 +404,12 @@ struct dvb_usb_adapter {
  *  Powered is in/decremented for each call to modify the state.
  * @udev: pointer to the device's struct usb_device.
  *
- * @usb_mutex: semaphore of USB control messages (reading needs two messages)
- * @i2c_mutex: semaphore for i2c-transfers
+ * @data_mutex: mutex to protect the data structure used to store URB data
+ * @usb_mutex: mutex of USB control messages (reading needs two messages).
+ *     Please notice that this mutex is used internally at the generic
+ *     URB control functions. So, drivers using dvb_usb_generic_rw() and
+ *     derivated functions should not lock it internally.
+ * @i2c_mutex: mutex for i2c-transfers
  *
  * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
  *
@@ -433,6 +437,7 @@ struct dvb_usb_device {
        int powered;
 
        /* locking */
+       struct mutex data_mutex;
        struct mutex usb_mutex;
 
        /* i2c */
index 5fb0c650926e3561684981013cc004a17975a290..2c720cb2fb00f0ddecd0eb82c6daf0f3a6731094 100644 (file)
@@ -852,7 +852,7 @@ static int su3000_power_ctrl(struct dvb_usb_device *d, int i)
        if (i && !state->initialized) {
                state->initialized = 1;
                /* reset board */
-               dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0);
+               return dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0);
        }
 
        return 0;
index 5d0384dd45b5ed1ed2e638acdddf9fe86ea2e628..993bb7a72985f05140b311c811f335db7258b7ec 100644 (file)
@@ -15,6 +15,7 @@
  * see Documentation/dvb/README.dvb-usb for more information
  */
 #include "gp8psk.h"
+#include "gp8psk-fe.h"
 
 /* debug */
 static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
@@ -24,37 +25,19 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DV
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
-{
-       return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6));
-}
-
-static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
-{
-       return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1));
-}
-
-static void gp8psk_info(struct dvb_usb_device *d)
-{
-       u8 fpga_vers, fw_vers[6];
-
-       if (!gp8psk_get_fw_version(d, fw_vers))
-               info("FW Version = %i.%02i.%i (0x%x)  Build %4i/%02i/%02i",
-               fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
-               2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
-       else
-               info("failed to get FW version");
-
-       if (!gp8psk_get_fpga_version(d, &fpga_vers))
-               info("FPGA Version = %i", fpga_vers);
-       else
-               info("failed to get FPGA version");
-}
+struct gp8psk_state {
+       unsigned char data[80];
+};
 
-int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+static int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
+                           u16 index, u8 *b, int blen)
 {
+       struct gp8psk_state *st = d->priv;
        int ret = 0,try = 0;
 
+       if (blen > sizeof(st->data))
+               return -EIO;
+
        if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
                return ret;
 
@@ -63,7 +46,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
                        usb_rcvctrlpipe(d->udev,0),
                        req,
                        USB_TYPE_VENDOR | USB_DIR_IN,
-                       value,index,b,blen,
+                       value, index, st->data, blen,
                        2000);
                deb_info("reading number %d (ret: %d)\n",try,ret);
                try++;
@@ -72,8 +55,10 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
        if (ret < 0 || ret != blen) {
                warn("usb in %d operation failed.", req);
                ret = -EIO;
-       } else
+       } else {
                ret = 0;
+               memcpy(b, st->data, blen);
+       }
 
        deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
        debug_dump(b,blen,deb_xfer);
@@ -83,22 +68,27 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
        return ret;
 }
 
-int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+static int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
                             u16 index, u8 *b, int blen)
 {
+       struct gp8psk_state *st = d->priv;
        int ret;
 
        deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
        debug_dump(b,blen,deb_xfer);
 
+       if (blen > sizeof(st->data))
+               return -EIO;
+
        if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
                return ret;
 
+       memcpy(st->data, b, blen);
        if (usb_control_msg(d->udev,
                        usb_sndctrlpipe(d->udev,0),
                        req,
                        USB_TYPE_VENDOR | USB_DIR_OUT,
-                       value,index,b,blen,
+                       value, index, st->data, blen,
                        2000) != blen) {
                warn("usb out operation failed.");
                ret = -EIO;
@@ -109,6 +99,34 @@ int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
        return ret;
 }
 
+
+static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
+{
+       return gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6);
+}
+
+static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
+{
+       return gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1);
+}
+
+static void gp8psk_info(struct dvb_usb_device *d)
+{
+       u8 fpga_vers, fw_vers[6];
+
+       if (!gp8psk_get_fw_version(d, fw_vers))
+               info("FW Version = %i.%02i.%i (0x%x)  Build %4i/%02i/%02i",
+               fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
+               2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
+       else
+               info("failed to get FW version");
+
+       if (!gp8psk_get_fpga_version(d, &fpga_vers))
+               info("FPGA Version = %i", fpga_vers);
+       else
+               info("failed to get FPGA version");
+}
+
 static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
 {
        int ret;
@@ -143,6 +161,11 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
                        err("failed to load bcm4500 firmware.");
                        goto out_free;
                }
+               if (buflen > 64) {
+                       err("firmare chunk size bigger than 64 bytes.");
+                       goto out_free;
+               }
+
                memcpy(buf, ptr, buflen);
                if (dvb_usb_generic_write(d, buf, buflen)) {
                        err("failed to load bcm4500 firmware.");
@@ -206,10 +229,13 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
        return 0;
 }
 
-int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+static int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
 {
        u8 buf;
        int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+
+       deb_xfer("reloading firmware\n");
+
        /* Turn off 8psk power */
        if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
                return -EINVAL;
@@ -228,9 +254,47 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
 }
 
+/* Callbacks for gp8psk-fe.c */
+
+static int gp8psk_fe_in(void *priv, u8 req, u16 value,
+                           u16 index, u8 *b, int blen)
+{
+       struct dvb_usb_device *d = priv;
+
+       return gp8psk_usb_in_op(d, req, value, index, b, blen);
+}
+
+static int gp8psk_fe_out(void *priv, u8 req, u16 value,
+                           u16 index, u8 *b, int blen)
+{
+       struct dvb_usb_device *d = priv;
+
+       return gp8psk_usb_out_op(d, req, value, index, b, blen);
+}
+
+static int gp8psk_fe_reload(void *priv)
+{
+       struct dvb_usb_device *d = priv;
+
+       return gp8psk_bcm4500_reload(d);
+}
+
+const struct gp8psk_fe_ops gp8psk_fe_ops = {
+       .in = gp8psk_fe_in,
+       .out = gp8psk_fe_out,
+       .reload = gp8psk_fe_reload,
+};
+
 static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev);
+       struct dvb_usb_device *d = adap->dev;
+       int id = le16_to_cpu(d->udev->descriptor.idProduct);
+       int is_rev1;
+
+       is_rev1 = (id == USB_PID_GENPIX_8PSK_REV_1_WARM) ? true : false;
+
+       adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach,
+                                        &gp8psk_fe_ops, d, is_rev1);
        return 0;
 }
 
@@ -265,6 +329,8 @@ static struct dvb_usb_device_properties gp8psk_properties = {
        .usb_ctrl = CYPRESS_FX2,
        .firmware = "dvb-usb-gp8psk-01.fw",
 
+       .size_of_priv = sizeof(struct gp8psk_state),
+
        .num_adapters = 1,
        .adapter = {
                {
index ed32b9da484364d8f49e94f4c29342149ef563da..d8975b866deeceda0e3820a7810f5cfc2b7205d6 100644 (file)
@@ -24,58 +24,6 @@ extern int dvb_usb_gp8psk_debug;
 #define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
 #define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
 #define deb_rc(args...)   dprintk(dvb_usb_gp8psk_debug,0x04,args)
-#define deb_fe(args...)   dprintk(dvb_usb_gp8psk_debug,0x08,args)
-
-/* Twinhan Vendor requests */
-#define TH_COMMAND_IN                     0xC0
-#define TH_COMMAND_OUT                    0xC1
-
-/* gp8psk commands */
-
-#define GET_8PSK_CONFIG                 0x80    /* in */
-#define SET_8PSK_CONFIG                 0x81
-#define I2C_WRITE                      0x83
-#define I2C_READ                       0x84
-#define ARM_TRANSFER                    0x85
-#define TUNE_8PSK                       0x86
-#define GET_SIGNAL_STRENGTH             0x87    /* in */
-#define LOAD_BCM4500                    0x88
-#define BOOT_8PSK                       0x89    /* in */
-#define START_INTERSIL                  0x8A    /* in */
-#define SET_LNB_VOLTAGE                 0x8B
-#define SET_22KHZ_TONE                  0x8C
-#define SEND_DISEQC_COMMAND             0x8D
-#define SET_DVB_MODE                    0x8E
-#define SET_DN_SWITCH                   0x8F
-#define GET_SIGNAL_LOCK                 0x90    /* in */
-#define GET_FW_VERS                    0x92
-#define GET_SERIAL_NUMBER               0x93    /* in */
-#define USE_EXTRA_VOLT                  0x94
-#define GET_FPGA_VERS                  0x95
-#define CW3K_INIT                      0x9d
-
-/* PSK_configuration bits */
-#define bm8pskStarted                   0x01
-#define bm8pskFW_Loaded                 0x02
-#define bmIntersilOn                    0x04
-#define bmDVBmode                       0x08
-#define bm22kHz                         0x10
-#define bmSEL18V                        0x20
-#define bmDCtuned                       0x40
-#define bmArmed                         0x80
-
-/* Satellite modulation modes */
-#define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
-#define ADV_MOD_TURBO_QPSK 1   /* Turbo QPSK */
-#define ADV_MOD_TURBO_8PSK 2   /* Turbo 8PSK (also used for Trellis 8PSK) */
-#define ADV_MOD_TURBO_16QAM 3  /* Turbo 16QAM (also used for Trellis 8PSK) */
-
-#define ADV_MOD_DCII_C_QPSK 4  /* Digicipher II Combo */
-#define ADV_MOD_DCII_I_QPSK 5  /* Digicipher II I-stream */
-#define ADV_MOD_DCII_Q_QPSK 6  /* Digicipher II Q-stream */
-#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
-#define ADV_MOD_DSS_QPSK 8     /* DSS (DIRECTV) QPSK */
-#define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
 
 #define GET_USB_SPEED                     0x07
 
@@ -86,15 +34,4 @@ extern int dvb_usb_gp8psk_debug;
 #define PRODUCT_STRING_READ               0x0D
 #define FW_BCD_VERSION_READ               0x14
 
-/* firmware revision id's */
-#define GP8PSK_FW_REV1                 0x020604
-#define GP8PSK_FW_REV2                 0x020704
-#define GP8PSK_FW_VERS(_fw_vers)       ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0])
-
-extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
-extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
-                            u16 index, u8 *b, int blen);
-extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
-
 #endif
index fc7569e2728d2201e14897cddd41c9a9504a9716..1babd334191069d30419e2c07fc25fd04e0931d4 100644 (file)
@@ -74,22 +74,31 @@ static struct rc_map_table rc_map_haupp_table[] = {
  */
 static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
+       u8 *buf, data, toggle, custom;
        u16 raw;
-       int i;
+       int i, ret;
        struct dibusb_device_state *st = d->priv;
 
-       dvb_usb_generic_rw(d,cmd,2,key,5,0);
+       buf = kmalloc(5, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = DIBUSB_REQ_POLL_REMOTE;
+       buf[1] = 0x35;
+       ret = dvb_usb_generic_rw(d, buf, 2, buf, 5, 0);
+       if (ret < 0)
+               goto ret;
 
        *state = REMOTE_NO_KEY_PRESSED;
-       switch (key[0]) {
+       switch (buf[0]) {
                case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
-                       raw = ((key[1] << 8) | key[2]) >> 3;
+                       raw = ((buf[1] << 8) | buf[2]) >> 3;
                        toggle = !!(raw & 0x800);
                        data = raw & 0x3f;
                        custom = (raw >> 6) & 0x1f;
 
-                       deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
+                       deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",
+                              buf[1], buf[2], buf[3], custom, data, toggle);
 
                        for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) {
                                if (rc5_data(&rc_map_haupp_table[i]) == data &&
@@ -117,7 +126,9 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                        break;
        }
 
-       return 0;
+ret:
+       kfree(buf);
+       return ret;
 }
 
 static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
index c05de1b088a4e3abf0e6de4309b43df6305d4678..07fa08be9e994a3f7d5952251b73f871fe4ecdca 100644 (file)
@@ -97,48 +97,53 @@ struct pctv452e_state {
        u8 c;      /* transaction counter, wraps around...  */
        u8 initialized; /* set to 1 if 0x15 has been sent */
        u16 last_rc_key;
+
+       unsigned char data[80];
 };
 
 static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
                         unsigned int write_len, unsigned int read_len)
 {
        struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-       u8 buf[64];
        u8 id;
        unsigned int rlen;
        int ret;
 
-       BUG_ON(NULL == data && 0 != (write_len | read_len));
-       BUG_ON(write_len > 64 - 4);
-       BUG_ON(read_len > 64 - 4);
+       if (!data || (write_len > 64 - 4) || (read_len > 64 - 4)) {
+               err("%s: transfer data invalid", __func__);
+               return -EIO;
+       }
 
+       mutex_lock(&state->ca_mutex);
        id = state->c++;
 
-       buf[0] = SYNC_BYTE_OUT;
-       buf[1] = id;
-       buf[2] = cmd;
-       buf[3] = write_len;
+       state->data[0] = SYNC_BYTE_OUT;
+       state->data[1] = id;
+       state->data[2] = cmd;
+       state->data[3] = write_len;
 
-       memcpy(buf + 4, data, write_len);
+       memcpy(state->data + 4, data, write_len);
 
        rlen = (read_len > 0) ? 64 : 0;
-       ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
-                                 buf, rlen, /* delay_ms */ 0);
+       ret = dvb_usb_generic_rw(d, state->data, 4 + write_len,
+                                 state->data, rlen, /* delay_ms */ 0);
        if (0 != ret)
                goto failed;
 
        ret = -EIO;
-       if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+       if (SYNC_BYTE_IN != state->data[0] || id != state->data[1])
                goto failed;
 
-       memcpy(data, buf + 4, read_len);
+       memcpy(data, state->data + 4, read_len);
 
+       mutex_unlock(&state->ca_mutex);
        return 0;
 
 failed:
        err("CI error %d; %02X %02X %02X -> %*ph.",
-            ret, SYNC_BYTE_OUT, id, cmd, 3, buf);
+            ret, SYNC_BYTE_OUT, id, cmd, 3, state->data);
 
+       mutex_unlock(&state->ca_mutex);
        return ret;
 }
 
@@ -405,52 +410,53 @@ static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr,
                                u8 *rcv_buf, u8 rcv_len)
 {
        struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-       u8 buf[64];
        u8 id;
        int ret;
 
+       mutex_lock(&state->ca_mutex);
        id = state->c++;
 
        ret = -EINVAL;
        if (snd_len > 64 - 7 || rcv_len > 64 - 7)
                goto failed;
 
-       buf[0] = SYNC_BYTE_OUT;
-       buf[1] = id;
-       buf[2] = PCTV_CMD_I2C;
-       buf[3] = snd_len + 3;
-       buf[4] = addr << 1;
-       buf[5] = snd_len;
-       buf[6] = rcv_len;
+       state->data[0] = SYNC_BYTE_OUT;
+       state->data[1] = id;
+       state->data[2] = PCTV_CMD_I2C;
+       state->data[3] = snd_len + 3;
+       state->data[4] = addr << 1;
+       state->data[5] = snd_len;
+       state->data[6] = rcv_len;
 
-       memcpy(buf + 7, snd_buf, snd_len);
+       memcpy(state->data + 7, snd_buf, snd_len);
 
-       ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
-                                 buf, /* rcv_len */ 64,
+       ret = dvb_usb_generic_rw(d, state->data, 7 + snd_len,
+                                 state->data, /* rcv_len */ 64,
                                  /* delay_ms */ 0);
        if (ret < 0)
                goto failed;
 
        /* TT USB protocol error. */
        ret = -EIO;
-       if (SYNC_BYTE_IN != buf[0] || id != buf[1])
+       if (SYNC_BYTE_IN != state->data[0] || id != state->data[1])
                goto failed;
 
        /* I2C device didn't respond as expected. */
        ret = -EREMOTEIO;
-       if (buf[5] < snd_len || buf[6] < rcv_len)
+       if (state->data[5] < snd_len || state->data[6] < rcv_len)
                goto failed;
 
-       memcpy(rcv_buf, buf + 7, rcv_len);
+       memcpy(rcv_buf, state->data + 7, rcv_len);
+       mutex_unlock(&state->ca_mutex);
 
        return rcv_len;
 
 failed:
-       err("I2C error %d; %02X %02X  %02X %02X %02X -> "
-            "%02X %02X  %02X %02X %02X.",
+       err("I2C error %d; %02X %02X  %02X %02X %02X -> %*ph",
             ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
-            buf[0], buf[1], buf[4], buf[5], buf[6]);
+            7, state->data);
 
+       mutex_unlock(&state->ca_mutex);
        return ret;
 }
 
@@ -499,8 +505,7 @@ static u32 pctv452e_i2c_func(struct i2c_adapter *adapter)
 static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
 {
        struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-       u8 b0[] = { 0xaa, 0, PCTV_CMD_RESET, 1, 0 };
-       u8 rx[PCTV_ANSWER_LEN];
+       u8 *rx;
        int ret;
 
        info("%s: %d\n", __func__, i);
@@ -511,6 +516,11 @@ static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
        if (state->initialized)
                return 0;
 
+       rx = kmalloc(PCTV_ANSWER_LEN, GFP_KERNEL);
+       if (!rx)
+               return -ENOMEM;
+
+       mutex_lock(&state->ca_mutex);
        /* hmm where shoud this should go? */
        ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
        if (ret != 0)
@@ -518,65 +528,75 @@ static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
                        __func__, ret);
 
        /* this is a one-time initialization, dont know where to put */
-       b0[1] = state->c++;
+       state->data[0] = 0xaa;
+       state->data[1] = state->c++;
+       state->data[2] = PCTV_CMD_RESET;
+       state->data[3] = 1;
+       state->data[4] = 0;
        /* reset board */
-       ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+       ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0);
        if (ret)
-               return ret;
+               goto ret;
 
-       b0[1] = state->c++;
-       b0[4] = 1;
+       state->data[1] = state->c++;
+       state->data[4] = 1;
        /* reset board (again?) */
-       ret = dvb_usb_generic_rw(d, b0, sizeof(b0), rx, PCTV_ANSWER_LEN, 0);
+       ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0);
        if (ret)
-               return ret;
+               goto ret;
 
        state->initialized = 1;
 
-       return 0;
+ret:
+       mutex_unlock(&state->ca_mutex);
+       kfree(rx);
+       return ret;
 }
 
 static int pctv452e_rc_query(struct dvb_usb_device *d)
 {
        struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
-       u8 b[CMD_BUFFER_SIZE];
-       u8 rx[PCTV_ANSWER_LEN];
        int ret, i;
-       u8 id = state->c++;
+       u8 id;
+
+       mutex_lock(&state->ca_mutex);
+       id = state->c++;
 
        /* prepare command header  */
-       b[0] = SYNC_BYTE_OUT;
-       b[1] = id;
-       b[2] = PCTV_CMD_IR;
-       b[3] = 0;
+       state->data[0] = SYNC_BYTE_OUT;
+       state->data[1] = id;
+       state->data[2] = PCTV_CMD_IR;
+       state->data[3] = 0;
 
        /* send ir request */
-       ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
+       ret = dvb_usb_generic_rw(d, state->data, 4,
+                                state->data, PCTV_ANSWER_LEN, 0);
        if (ret != 0)
-               return ret;
+               goto ret;
 
        if (debug > 3) {
-               info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx);
-               for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
-                       info(" %02x", rx[i+3]);
+               info("%s: read: %2d: %*ph: ", __func__, ret, 3, state->data);
+               for (i = 0; (i < state->data[3]) && ((i + 3) < PCTV_ANSWER_LEN); i++)
+                       info(" %02x", state->data[i + 3]);
 
                info("\n");
        }
 
-       if ((rx[3] == 9) &&  (rx[12] & 0x01)) {
+       if ((state->data[3] == 9) &&  (state->data[12] & 0x01)) {
                /* got a "press" event */
-               state->last_rc_key = RC_SCANCODE_RC5(rx[7], rx[6]);
+               state->last_rc_key = RC_SCANCODE_RC5(state->data[7], state->data[6]);
                if (debug > 2)
                        info("%s: cmd=0x%02x sys=0x%02x\n",
-                               __func__, rx[6], rx[7]);
+                               __func__, state->data[6], state->data[7]);
 
                rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_rc_key, 0);
        } else if (state->last_rc_key) {
                rc_keyup(d->rc_dev);
                state->last_rc_key = 0;
        }
-
-       return 0;
+ret:
+       mutex_unlock(&state->ca_mutex);
+       return ret;
 }
 
 static int pctv452e_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
index d9f3262bf0712642b6d15edd216a26ee48c7ecf9..4706628a3ed5ea5345e30a9dc59cad7fb385286d 100644 (file)
@@ -89,9 +89,13 @@ struct technisat_usb2_state {
 static int technisat_usb2_i2c_access(struct usb_device *udev,
                u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
 {
-       u8 b[64];
+       u8 *b;
        int ret, actual_length;
 
+       b = kmalloc(64, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+
        deb_i2c("i2c-access: %02x, tx: ", device_addr);
        debug_dump(tx, txlen, deb_i2c);
        deb_i2c(" ");
@@ -123,7 +127,7 @@ static int technisat_usb2_i2c_access(struct usb_device *udev,
 
        if (ret < 0) {
                err("i2c-error: out failed %02x = %d", device_addr, ret);
-               return -ENODEV;
+               goto err;
        }
 
        ret = usb_bulk_msg(udev,
@@ -131,7 +135,7 @@ static int technisat_usb2_i2c_access(struct usb_device *udev,
                        b, 64, &actual_length, 1000);
        if (ret < 0) {
                err("i2c-error: in failed %02x = %d", device_addr, ret);
-               return -ENODEV;
+               goto err;
        }
 
        if (b[0] != I2C_STATUS_OK) {
@@ -140,7 +144,7 @@ static int technisat_usb2_i2c_access(struct usb_device *udev,
                if (!(b[0] == I2C_STATUS_NAK &&
                                device_addr == 0x60
                                /* && device_is_technisat_usb2 */))
-                       return -ENODEV;
+                       goto err;
        }
 
        deb_i2c("status: %d, ", b[0]);
@@ -154,7 +158,9 @@ static int technisat_usb2_i2c_access(struct usb_device *udev,
 
        deb_i2c("\n");
 
-       return 0;
+err:
+       kfree(b);
+       return ret;
 }
 
 static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
index c3a0e87066ebbbd78cda420a48f7dc76ab511107..f7bb78c1873c915d9db9574ea024cc77a355c413 100644 (file)
@@ -1901,19 +1901,30 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request,
                             s32 TransferBufferLength, int bOut)
 {
        int r;
+       unsigned char *buf;
+
+       buf = kmalloc(TransferBufferLength, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        if (!bOut) {
                r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                                    Request,
                                    USB_TYPE_VENDOR | USB_RECIP_DEVICE |
                                    USB_DIR_IN,
-                                   Value, Index, TransferBuffer,
+                                   Value, Index, buf,
                                    TransferBufferLength, HZ * 5);
+
+               if (r >= 0)
+                       memcpy(TransferBuffer, buf, TransferBufferLength);
        } else {
+               memcpy(buf, TransferBuffer, TransferBufferLength);
                r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                                    Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                                   Value, Index, TransferBuffer,
+                                   Value, Index, buf,
                                    TransferBufferLength, HZ * 5);
        }
+       kfree(buf);
        return r;
 }
 
index db200c9d796d3683d23b9279db73d6eb625420da..22a9aae16291b31adb5eeae0af4cd14c747c0ec5 100644 (file)
@@ -147,20 +147,26 @@ int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
 int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value)
 {
        struct usb_device *udev = dev->udev;
+       unsigned char *buf;
        int ret;
 
+       buf = kmalloc(sizeof(u8), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                        0x00,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0x00,
                        index,
-                       (u8 *) value,
+                       buf,
                        sizeof(u8),
                        500);
-       if (ret < 0)
-               return ret;
-       else
-               return 0;
+       if (ret >= 0)
+               memcpy(value, buf, sizeof(u8));
+
+       kfree(buf);
+       return ret;
 }
 
 static int stk_start_stream(struct stk_camera *dev)
index f300f060b3f34cdfeb8b1e12b90d9ab345c6b629..1db0af6c7f94810bf9270b0ebb5961de6b1802a5 100644 (file)
@@ -156,6 +156,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
 {
        unsigned long first, last;
        int err, rw = 0;
+       unsigned int flags = FOLL_FORCE;
 
        dma->direction = direction;
        switch (dma->direction) {
@@ -178,12 +179,14 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
        if (NULL == dma->pages)
                return -ENOMEM;
 
+       if (rw == READ)
+               flags |= FOLL_WRITE;
+
        dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
                data, size, dma->nr_pages);
 
        err = get_user_pages(data & PAGE_MASK, dma->nr_pages,
-                            rw == READ, 1, /* force */
-                            dma->pages, NULL);
+                            flags, dma->pages, NULL);
 
        if (err != dma->nr_pages) {
                dma->nr_pages = (err >= 0) ? err : 0;
index 3c3b517f1d1cacb5a7131263cd80c112bd22d619..1cd322e939c70520e9e915575590bf516c0e46ee 100644 (file)
@@ -42,6 +42,10 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
        unsigned long first, last;
        unsigned long nr;
        struct frame_vector *vec;
+       unsigned int flags = FOLL_FORCE;
+
+       if (write)
+               flags |= FOLL_WRITE;
 
        first = start >> PAGE_SHIFT;
        last = (start + length - 1) >> PAGE_SHIFT;
@@ -49,7 +53,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
        vec = frame_vector_create(nr);
        if (!vec)
                return ERR_PTR(-ENOMEM);
-       ret = get_vaddr_frames(start & PAGE_MASK, nr, write, true, vec);
+       ret = get_vaddr_frames(start & PAGE_MASK, nr, flags, vec);
        if (ret < 0)
                goto out_destroy;
        /* We accept only complete set of PFNs */
index d34bc35303851634d143f924a790a47a7f006e8c..2e3cf012ef485f863dd2de36d26dae8caae7156b 100644 (file)
@@ -524,6 +524,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
        int rc;
 
        if (!host->req) {
+               pm_runtime_get_sync(ms_dev(host));
                do {
                        rc = memstick_next_req(msh, &host->req);
                        dev_dbg(ms_dev(host), "next req %d\n", rc);
@@ -544,6 +545,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
                                                host->req->error);
                        }
                } while (!rc);
+               pm_runtime_put(ms_dev(host));
        }
 
 }
@@ -570,6 +572,7 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
        dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
                        __func__, param, value);
 
+       pm_runtime_get_sync(ms_dev(host));
        mutex_lock(&ucr->dev_mutex);
 
        err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD);
@@ -635,6 +638,7 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
        }
 out:
        mutex_unlock(&ucr->dev_mutex);
+       pm_runtime_put(ms_dev(host));
 
        /* power-on delay */
        if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON)
@@ -681,6 +685,7 @@ static int rtsx_usb_detect_ms_card(void *__host)
        int err;
 
        for (;;) {
+               pm_runtime_get_sync(ms_dev(host));
                mutex_lock(&ucr->dev_mutex);
 
                /* Check pending MS card changes */
@@ -703,6 +708,7 @@ static int rtsx_usb_detect_ms_card(void *__host)
                }
 
 poll_again:
+               pm_runtime_put(ms_dev(host));
                if (host->eject)
                        break;
 
index 3228fd182a99ecfd32391f90d41d61be46b0251c..9ff243970e93ef1c025df40ca3e4474f59c371f5 100644 (file)
@@ -123,19 +123,6 @@ static const struct intel_lpss_platform_info apl_i2c_info = {
        .properties = apl_i2c_properties,
 };
 
-static const struct intel_lpss_platform_info kbl_info = {
-       .clk_rate = 120000000,
-};
-
-static const struct intel_lpss_platform_info kbl_uart_info = {
-       .clk_rate = 120000000,
-       .clk_con_id = "baudclk",
-};
-
-static const struct intel_lpss_platform_info kbl_i2c_info = {
-       .clk_rate = 133000000,
-};
-
 static const struct pci_device_id intel_lpss_pci_ids[] = {
        /* BXT A-Step */
        { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
@@ -207,15 +194,15 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info },
        { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info },
        /* KBL-H */
-       { PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&kbl_uart_info },
-       { PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&kbl_uart_info },
-       { PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&kbl_info },
-       { PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&kbl_info },
-       { PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&kbl_i2c_info },
-       { PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&kbl_i2c_info },
-       { PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&kbl_i2c_info },
-       { PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&kbl_i2c_info },
-       { PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&kbl_uart_info },
+       { PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&spt_uart_info },
+       { PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&spt_uart_info },
+       { PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&spt_info },
+       { PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&spt_info },
+       { PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&spt_i2c_info },
+       { PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&spt_uart_info },
        { }
 };
 MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
index 41b113875d6452acc545085ffbc4c52c23079338..70c646b0097d8c70ded6c4f62a92711aa89bfd22 100644 (file)
@@ -502,9 +502,6 @@ int intel_lpss_suspend(struct device *dev)
        for (i = 0; i < LPSS_PRIV_REG_COUNT; i++)
                lpss->priv_ctx[i] = readl(lpss->priv + i * 4);
 
-       /* Put the device into reset state */
-       writel(0, lpss->priv + LPSS_PRIV_RESETS);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(intel_lpss_suspend);
index 43e54b7e908f0cc5a117f950db323ebfa6b246cf..f9a8c5203873a2f8b6ac4a68e5582eddd69b3103 100644 (file)
@@ -86,6 +86,7 @@ enum bxtwc_irqs_level2 {
        BXTWC_THRM2_IRQ,
        BXTWC_BCU_IRQ,
        BXTWC_ADC_IRQ,
+       BXTWC_USBC_IRQ,
        BXTWC_CHGR0_IRQ,
        BXTWC_CHGR1_IRQ,
        BXTWC_GPIO0_IRQ,
@@ -111,7 +112,8 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
        REGMAP_IRQ_REG(BXTWC_THRM2_IRQ, 2, 0xff),
        REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 3, 0x1f),
        REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 4, 0xff),
-       REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x3f),
+       REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 5, BIT(5)),
+       REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x1f),
        REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 6, 0x1f),
        REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 7, 0xff),
        REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 8, 0x3f),
@@ -146,7 +148,7 @@ static struct resource adc_resources[] = {
 };
 
 static struct resource usbc_resources[] = {
-       DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "USBC"),
+       DEFINE_RES_IRQ(BXTWC_USBC_IRQ),
 };
 
 static struct resource charger_resources[] = {
index 3ac486a597f3c31e8e362f1f9954098cdf081086..c57e407020f11dd19aff3a9dd4b9ba7ce9c7b351 100644 (file)
@@ -399,6 +399,8 @@ int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones)
                                        clones[i]);
        }
 
+       put_device(dev);
+
        return 0;
 }
 EXPORT_SYMBOL(mfd_clone_cell);
index cfdae8a3d77976b3a5b543551d07834069a7b45d..b0c7bcdaf5df522f9d1a208fe325cf053c063fab 100644 (file)
@@ -851,6 +851,8 @@ static int stmpe_reset(struct stmpe *stmpe)
        if (ret < 0)
                return ret;
 
+       msleep(10);
+
        timeout = jiffies + msecs_to_jiffies(100);
        while (time_before(jiffies, timeout)) {
                ret = __stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL]);
index 2f2225e845efe960a9904fefc1d16fc5cde6b081..b93fe4c4957a06c947650ae67987cec11aca7d48 100644 (file)
@@ -73,8 +73,10 @@ static struct syscon *of_syscon_register(struct device_node *np)
        /* Parse the device's DT node for an endianness specification */
        if (of_property_read_bool(np, "big-endian"))
                syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
-        else if (of_property_read_bool(np, "little-endian"))
+       else if (of_property_read_bool(np, "little-endian"))
                syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
+       else if (of_property_read_bool(np, "native-endian"))
+               syscon_config.val_format_endian = REGMAP_ENDIAN_NATIVE;
 
        /*
         * search for reg-io-width property in DT. If it is not provided,
index 7eec619a6023c717803d05e318537e0589f6967e..8588dbad330119149ad112c0bf493e1c979d59a3 100644 (file)
@@ -393,8 +393,13 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                BUG();
                goto err;
        }
-               
-       ret = devm_regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
+
+       /*
+        * Can't use devres helper here as some of the supplies are provided by
+        * wm8994->dev's children (regulators) and those regulators are
+        * unregistered by the devres core before the supplies are freed.
+        */
+       ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
                                 wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
@@ -405,7 +410,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                                    wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
-               goto err;
+               goto err_regulator_free;
        }
 
        ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET);
@@ -596,6 +601,8 @@ err_irq:
 err_enable:
        regulator_bulk_disable(wm8994->num_supplies,
                               wm8994->supplies);
+err_regulator_free:
+       regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
 err:
        mfd_remove_devices(wm8994->dev);
        return ret;
@@ -604,10 +611,11 @@ err:
 static void wm8994_device_exit(struct wm8994 *wm8994)
 {
        pm_runtime_disable(wm8994->dev);
-       mfd_remove_devices(wm8994->dev);
        wm8994_irq_exit(wm8994);
        regulator_bulk_disable(wm8994->num_supplies,
                               wm8994->supplies);
+       regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
+       mfd_remove_devices(wm8994->dev);
 }
 
 static const struct of_device_id wm8994_of_match[] = {
index f3d34b941f8599e91e121b7dfe8cbc115e9f138e..2e5233b6097110e72ae147f21ed15cf259b0a5a9 100644 (file)
@@ -229,6 +229,14 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed,
        if (ctx->status == STARTED)
                goto out; /* already started */
 
+       /*
+        * Increment the mapped context count for adapter. This also checks
+        * if adapter_context_lock is taken.
+        */
+       rc = cxl_adapter_context_get(ctx->afu->adapter);
+       if (rc)
+               goto out;
+
        if (task) {
                ctx->pid = get_task_pid(task, PIDTYPE_PID);
                ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID);
@@ -239,7 +247,10 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed,
        cxl_ctx_get();
 
        if ((rc = cxl_ops->attach_process(ctx, kernel, wed, 0))) {
+               put_pid(ctx->glpid);
                put_pid(ctx->pid);
+               ctx->glpid = ctx->pid = NULL;
+               cxl_adapter_context_put(ctx->afu->adapter);
                cxl_ctx_put();
                goto out;
        }
index c466ee2b0c973a7c77cb16566770dec3b426db33..5e506c19108ad22da4a002957fd056711138b0f3 100644 (file)
@@ -238,6 +238,9 @@ int __detach_context(struct cxl_context *ctx)
        put_pid(ctx->glpid);
 
        cxl_ctx_put();
+
+       /* Decrease the attached context count on the adapter */
+       cxl_adapter_context_put(ctx->afu->adapter);
        return 0;
 }
 
index 01d372aba131416524ec565748ea4f9e52a795ee..a144073593fa1e5170bba669d7ba467eb06ada5b 100644 (file)
@@ -618,6 +618,14 @@ struct cxl {
        bool perst_select_user;
        bool perst_same_image;
        bool psl_timebase_synced;
+
+       /*
+        * number of contexts mapped on to this card. Possible values are:
+        * >0: Number of contexts mapped and new one can be mapped.
+        *  0: No active contexts and new ones can be mapped.
+        * -1: No contexts mapped and new ones cannot be mapped.
+        */
+       atomic_t contexts_num;
 };
 
 int cxl_pci_alloc_one_irq(struct cxl *adapter);
@@ -944,4 +952,20 @@ bool cxl_pci_is_vphb_device(struct pci_dev *dev);
 
 /* decode AFU error bits in the PSL register PSL_SERR_An */
 void cxl_afu_decode_psl_serr(struct cxl_afu *afu, u64 serr);
+
+/*
+ * Increments the number of attached contexts on an adapter.
+ * In case an adapter_context_lock is taken the return -EBUSY.
+ */
+int cxl_adapter_context_get(struct cxl *adapter);
+
+/* Decrements the number of attached contexts on an adapter */
+void cxl_adapter_context_put(struct cxl *adapter);
+
+/* If no active contexts then prevents contexts from being attached */
+int cxl_adapter_context_lock(struct cxl *adapter);
+
+/* Unlock the contexts-lock if taken. Warn and force unlock otherwise */
+void cxl_adapter_context_unlock(struct cxl *adapter);
+
 #endif
index 5fb9894b157faaae236fd75d4b41cceba069b3d1..77080cc5fa0aa4cdbc476729e4cdabcac8afae7b 100644 (file)
@@ -193,6 +193,16 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
 
        ctx->mmio_err_ff = !!(work.flags & CXL_START_WORK_ERR_FF);
 
+       /*
+        * Increment the mapped context count for adapter. This also checks
+        * if adapter_context_lock is taken.
+        */
+       rc = cxl_adapter_context_get(ctx->afu->adapter);
+       if (rc) {
+               afu_release_irqs(ctx, ctx);
+               goto out;
+       }
+
        /*
         * We grab the PID here and not in the file open to allow for the case
         * where a process (master, some daemon, etc) has opened the chardev on
@@ -205,11 +215,16 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
        ctx->pid = get_task_pid(current, PIDTYPE_PID);
        ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID);
 
+
        trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
 
        if ((rc = cxl_ops->attach_process(ctx, false, work.work_element_descriptor,
                                                        amr))) {
                afu_release_irqs(ctx, ctx);
+               cxl_adapter_context_put(ctx->afu->adapter);
+               put_pid(ctx->glpid);
+               put_pid(ctx->pid);
+               ctx->glpid = ctx->pid = NULL;
                goto out;
        }
 
index 9aa58a77a24d13f102546a9c45aa48d780326364..3e102cd6ed914d992152128423cce8cbab33e830 100644 (file)
@@ -1152,6 +1152,9 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic
        if ((rc = cxl_sysfs_adapter_add(adapter)))
                goto err_put1;
 
+       /* release the context lock as the adapter is configured */
+       cxl_adapter_context_unlock(adapter);
+
        return adapter;
 
 err_put1:
index d9be23b24aa3b88dce63a8c3f1bf38f9c66ca5ef..62e0dfb5f15b62d64980bb008d448038f8fd3c36 100644 (file)
@@ -243,8 +243,10 @@ struct cxl *cxl_alloc_adapter(void)
        if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))
                goto err2;
 
-       return adapter;
+       /* start with context lock taken */
+       atomic_set(&adapter->contexts_num, -1);
 
+       return adapter;
 err2:
        cxl_remove_adapter_nr(adapter);
 err1:
@@ -286,6 +288,44 @@ int cxl_afu_select_best_mode(struct cxl_afu *afu)
        return 0;
 }
 
+int cxl_adapter_context_get(struct cxl *adapter)
+{
+       int rc;
+
+       rc = atomic_inc_unless_negative(&adapter->contexts_num);
+       return rc >= 0 ? 0 : -EBUSY;
+}
+
+void cxl_adapter_context_put(struct cxl *adapter)
+{
+       atomic_dec_if_positive(&adapter->contexts_num);
+}
+
+int cxl_adapter_context_lock(struct cxl *adapter)
+{
+       int rc;
+       /* no active contexts -> contexts_num == 0 */
+       rc = atomic_cmpxchg(&adapter->contexts_num, 0, -1);
+       return rc ? -EBUSY : 0;
+}
+
+void cxl_adapter_context_unlock(struct cxl *adapter)
+{
+       int val = atomic_cmpxchg(&adapter->contexts_num, -1, 0);
+
+       /*
+        * contexts lock taken -> contexts_num == -1
+        * If not true then show a warning and force reset the lock.
+        * This will happen when context_unlock was requested without
+        * doing a context_lock.
+        */
+       if (val != -1) {
+               atomic_set(&adapter->contexts_num, 0);
+               WARN(1, "Adapter context unlocked with %d active contexts",
+                    val);
+       }
+}
+
 static int __init init_cxl(void)
 {
        int rc = 0;
index 7afad8477ad55358f3608abefcf85795407a99a1..e96be9ca4e60437db6bfba9b098fad852790f722 100644 (file)
@@ -1487,6 +1487,8 @@ static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev)
        if ((rc = cxl_native_register_psl_err_irq(adapter)))
                goto err;
 
+       /* Release the context lock as adapter is configured */
+       cxl_adapter_context_unlock(adapter);
        return 0;
 
 err:
index b043c20f158f122d11bbf5dc765ae957ebf9155d..a8b6d6a635e962b057325d9d5d6af96382474eba 100644 (file)
@@ -75,12 +75,31 @@ static ssize_t reset_adapter_store(struct device *device,
        int val;
 
        rc = sscanf(buf, "%i", &val);
-       if ((rc != 1) || (val != 1))
+       if ((rc != 1) || (val != 1 && val != -1))
                return -EINVAL;
 
-       if ((rc = cxl_ops->adapter_reset(adapter)))
-               return rc;
-       return count;
+       /*
+        * See if we can lock the context mapping that's only allowed
+        * when there are no contexts attached to the adapter. Once
+        * taken this will also prevent any context from getting activated.
+        */
+       if (val == 1) {
+               rc =  cxl_adapter_context_lock(adapter);
+               if (rc)
+                       goto out;
+
+               rc = cxl_ops->adapter_reset(adapter);
+               /* In case reset failed release context lock */
+               if (rc)
+                       cxl_adapter_context_unlock(adapter);
+
+       } else if (val == -1) {
+               /* Perform a forced adapter reset */
+               rc = cxl_ops->adapter_reset(adapter);
+       }
+
+out:
+       return rc ? rc : count;
 }
 
 static ssize_t load_image_on_perst_show(struct device *device,
index 8a679ecc8fd108d25ac4ecae8f1f24a33890107e..fc2794b513faf12ca043e760524046ad2d72a9ed 100644 (file)
@@ -352,17 +352,27 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
                if (copy_from_user(sgl->lpage, user_addr + user_size -
                                   sgl->lpage_size, sgl->lpage_size)) {
                        rc = -EFAULT;
-                       goto err_out1;
+                       goto err_out2;
                }
        }
        return 0;
 
+ err_out2:
+       __genwqe_free_consistent(cd, PAGE_SIZE, sgl->lpage,
+                                sgl->lpage_dma_addr);
+       sgl->lpage = NULL;
+       sgl->lpage_dma_addr = 0;
  err_out1:
        __genwqe_free_consistent(cd, PAGE_SIZE, sgl->fpage,
                                 sgl->fpage_dma_addr);
+       sgl->fpage = NULL;
+       sgl->fpage_dma_addr = 0;
  err_out:
        __genwqe_free_consistent(cd, sgl->sgl_size, sgl->sgl,
                                 sgl->sgl_dma_addr);
+       sgl->sgl = NULL;
+       sgl->sgl_dma_addr = 0;
+       sgl->sgl_size = 0;
        return -ENOMEM;
 }
 
index e9e6ea3ab73cf3500657d8c6001cb4eff5712568..75b9d4ac8b1e37fa3eb317aa728a4024c530539e 100644 (file)
@@ -178,7 +178,7 @@ static int mei_nfc_if_version(struct mei_cl *cl,
 
        ret = 0;
        bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
-       if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+       if (bytes_recv < if_version_length) {
                dev_err(bus->dev, "Could not read IF version\n");
                ret = -EIO;
                goto err;
index e6e5e55a12ed45f09577899198e7a8735ae7a0e8..60415a2bfcbd4c3f67a832bf3bc388b0af9a1270 100644 (file)
@@ -981,11 +981,13 @@ static bool mei_txe_check_and_ack_intrs(struct mei_device *dev, bool do_ack)
        hisr = mei_txe_br_reg_read(hw, HISR_REG);
 
        aliveness = mei_txe_aliveness_get(dev);
-       if (hhisr & IPC_HHIER_SEC && aliveness)
+       if (hhisr & IPC_HHIER_SEC && aliveness) {
                ipc_isr = mei_txe_sec_reg_read_silent(hw,
                                SEC_IPC_HOST_INT_STATUS_REG);
-       else
+       } else {
                ipc_isr = 0;
+               hhisr &= ~IPC_HHIER_SEC;
+       }
 
        generated = generated ||
                (hisr & HISR_INT_STS_MSK) ||
index e0203b1a20fd17fe88d9db3dc882d4d64eed2cc5..f806a4471eb913f388042886de29ec8de996cbf5 100644 (file)
@@ -1396,8 +1396,7 @@ retry:
                pinned_pages->nr_pages = get_user_pages(
                                (u64)addr,
                                nr_pages,
-                               !!(prot & SCIF_PROT_WRITE),
-                               0,
+                               (prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0,
                                pinned_pages->pages,
                                NULL);
                up_write(&mm->mmap_sem);
index a2d97b9b17e3463cebea03c70ec062cafcdac08c..6fb773dbcd0c3233d62136dcf673afb7b80efcea 100644 (file)
@@ -198,7 +198,7 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
 #else
        *pageshift = PAGE_SHIFT;
 #endif
-       if (get_user_pages(vaddr, 1, write, 0, &page, NULL) <= 0)
+       if (get_user_pages(vaddr, 1, write ? FOLL_WRITE : 0, &page, NULL) <= 0)
                return -EFAULT;
        *paddr = page_to_phys(page);
        put_page(page);
index 1525870f460aa65d0aa1b24baf119cb490ca35ed..33741ad4a74a0ee19af50cac294d52f5aa5726ab 100644 (file)
@@ -283,7 +283,7 @@ static void gru_unload_mm_tracker(struct gru_state *gru,
        spin_lock(&gru->gs_asid_lock);
        BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap);
        asids->mt_ctxbitmap ^= ctxbitmap;
-       gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n",
+       gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum %d, asidmap 0x%lx\n",
                gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0]);
        spin_unlock(&gru->gs_asid_lock);
        spin_unlock(&gms->ms_asid_lock);
index a8cee33ae8d2eaa6187945026e307168c96d0b45..b3fa738ae0050b48ba3f07ef3a02460d72898ea4 100644 (file)
@@ -431,6 +431,12 @@ int vmci_doorbell_create(struct vmci_handle *handle,
        if (vmci_handle_is_invalid(*handle)) {
                u32 context_id = vmci_get_context_id();
 
+               if (context_id == VMCI_INVALID_ID) {
+                       pr_warn("Failed to get context ID\n");
+                       result = VMCI_ERROR_NO_RESOURCES;
+                       goto free_mem;
+               }
+
                /* Let resource code allocate a free ID for us */
                new_handle = vmci_make_handle(context_id, VMCI_INVALID_ID);
        } else {
@@ -525,7 +531,7 @@ int vmci_doorbell_destroy(struct vmci_handle handle)
 
        entry = container_of(resource, struct dbell_entry, resource);
 
-       if (vmci_guest_code_active()) {
+       if (!hlist_unhashed(&entry->node)) {
                int result;
 
                dbell_index_table_remove(entry);
index 896be150e28fa5e0802f85e47cf882fe2ea4104d..d7eaf1eb11e7f3e67646dd7da053213a78fd35bd 100644 (file)
@@ -113,5 +113,5 @@ module_exit(vmci_drv_exit);
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.1.4.0-k");
+MODULE_VERSION("1.1.5.0-k");
 MODULE_LICENSE("GPL v2");
index c3335112e68c29cfe4a16eae0aabf4368682d357..709a872ed484a9da1ce620238c3222190c612f86 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/uaccess.h>
 
 #include "queue.h"
+#include "block.h"
 
 MODULE_ALIAS("mmc:block");
 #ifdef MODULE_PARAM_PREFIX
@@ -1786,7 +1787,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
        struct mmc_blk_data *md = mq->data;
        struct mmc_packed *packed = mqrq->packed;
        bool do_rel_wr, do_data_tag;
-       u32 *packed_cmd_hdr;
+       __le32 *packed_cmd_hdr;
        u8 hdr_blocks;
        u8 i = 1;
 
index 5a8dc5a76e0dffae3fef30d3eb93591994d733c8..3678220964fe62948a9a4d1aa2fed06b9c1a3a66 100644 (file)
@@ -2347,7 +2347,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
        struct mmc_test_req *rq = mmc_test_req_alloc();
        struct mmc_host *host = test->card->host;
        struct mmc_test_area *t = &test->area;
-       struct mmc_async_req areq;
+       struct mmc_test_async_req test_areq = { .test = test };
        struct mmc_request *mrq;
        unsigned long timeout;
        bool expired = false;
@@ -2363,8 +2363,8 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
                mrq->sbc = &rq->sbc;
        mrq->cap_cmd_during_tfr = true;
 
-       areq.mrq = mrq;
-       areq.err_check = mmc_test_check_result_async;
+       test_areq.areq.mrq = mrq;
+       test_areq.areq.err_check = mmc_test_check_result_async;
 
        mmc_test_prepare_mrq(test, mrq, t->sg, t->sg_len, dev_addr, t->blocks,
                             512, write);
@@ -2378,7 +2378,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
 
        /* Start ongoing data request */
        if (use_areq) {
-               mmc_start_req(host, &areq, &ret);
+               mmc_start_req(host, &test_areq.areq, &ret);
                if (ret)
                        goto out_free;
        } else {
index 3c15a75bae862d0466ad0ca43bef2b5e49ba13ed..342f1e3f301e9e6e7d0cc918f3f38aae32a88480 100644 (file)
@@ -31,7 +31,7 @@ enum mmc_packed_type {
 
 struct mmc_packed {
        struct list_head        list;
-       u32                     cmd_hdr[1024];
+       __le32                  cmd_hdr[1024];
        unsigned int            blocks;
        u8                      nr_entries;
        u8                      retries;
index 3486bc7fbb64a67a4cf1156c2ac7652541ef60bb..df19777068a6237f388bb4bb9c1a8ee6917ea64b 100644 (file)
@@ -26,6 +26,8 @@
 #include "mmc_ops.h"
 #include "sd_ops.h"
 
+#define DEFAULT_CMD6_TIMEOUT_MS        500
+
 static const unsigned int tran_exp[] = {
        10000,          100000,         1000000,        10000000,
        0,              0,              0,              0
@@ -571,6 +573,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                card->erased_byte = 0x0;
 
        /* eMMC v4.5 or later */
+       card->ext_csd.generic_cmd6_time = DEFAULT_CMD6_TIMEOUT_MS;
        if (card->ext_csd.rev >= 6) {
                card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
 
@@ -1263,6 +1266,16 @@ static int mmc_select_hs400es(struct mmc_card *card)
                goto out_err;
        }
 
+       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
+               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+       if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
+               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+       /* If fails try again during next card power cycle */
+       if (err)
+               goto out_err;
+
        err = mmc_select_bus_width(card);
        if (err < 0)
                goto out_err;
@@ -1272,6 +1285,8 @@ static int mmc_select_hs400es(struct mmc_card *card)
        if (err)
                goto out_err;
 
+       mmc_set_clock(host, card->ext_csd.hs_max_dtr);
+
        err = mmc_switch_status(card);
        if (err)
                goto out_err;
index c0bb0c793e84b2744586db19a5f559f31d207cd2..dbbc4303bdd0fb2ce0fa6c5d478b0f5a9f1ed70b 100644 (file)
@@ -46,12 +46,13 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        host->pdata = pdev->dev.platform_data;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       /* Get registers' physical base address */
-       host->phy_regs = regs->start;
        host->regs = devm_ioremap_resource(&pdev->dev, regs);
        if (IS_ERR(host->regs))
                return PTR_ERR(host->regs);
 
+       /* Get registers' physical base address */
+       host->phy_regs = regs->start;
+
        platform_set_drvdata(pdev, host);
        return dw_mci_probe(host);
 }
index 4fcbc4012ed03b554185cf42eeb1567b915745f6..df478ae72e23235ca8939128b2ad37497aaf4b71 100644 (file)
@@ -1058,6 +1058,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
        spin_unlock_irqrestore(&host->irq_lock, irqflags);
 
        if (host->dma_ops->start(host, sg_len)) {
+               host->dma_ops->stop(host);
                /* We can't do DMA, try PIO for this one */
                dev_dbg(host->dev,
                        "%s: fall back to PIO mode for current transfer\n",
@@ -2940,7 +2941,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
                return ERR_PTR(-ENOMEM);
 
        /* find reset controller when exist */
-       pdata->rstc = devm_reset_control_get_optional(dev, NULL);
+       pdata->rstc = devm_reset_control_get_optional(dev, "reset");
        if (IS_ERR(pdata->rstc)) {
                if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER)
                        return ERR_PTR(-EPROBE_DEFER);
index d839147e591d24f5d5d0a97d389ea04ffbaa9883..44ecebd1ea8c1834a5d311fbe36ddfc8383e3ecd 100644 (file)
@@ -661,13 +661,13 @@ static int mxs_mmc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, mmc);
 
+       spin_lock_init(&host->lock);
+
        ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0,
                               dev_name(&pdev->dev), host);
        if (ret)
                goto out_free_dma;
 
-       spin_lock_init(&host->lock);
-
        ret = mmc_add_host(mmc);
        if (ret)
                goto out_free_dma;
index 4106295527b9d0c5a4128f44e09c190791328ca9..6e9c0f8fddb1064c64c195812fdf8ad220728360 100644 (file)
@@ -1138,11 +1138,6 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        dev_dbg(sdmmc_dev(host), "%s\n", __func__);
        mutex_lock(&ucr->dev_mutex);
 
-       if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) {
-               mutex_unlock(&ucr->dev_mutex);
-               return;
-       }
-
        sd_set_power_mode(host, ios->power_mode);
        sd_set_bus_width(host, ios->bus_width);
        sd_set_timing(host, ios->timing, &host->ddr_mode);
@@ -1314,6 +1309,7 @@ static void rtsx_usb_update_led(struct work_struct *work)
                container_of(work, struct rtsx_usb_sdmmc, led_work);
        struct rtsx_ucr *ucr = host->ucr;
 
+       pm_runtime_get_sync(sdmmc_dev(host));
        mutex_lock(&ucr->dev_mutex);
 
        if (host->led.brightness == LED_OFF)
@@ -1322,6 +1318,7 @@ static void rtsx_usb_update_led(struct work_struct *work)
                rtsx_usb_turn_on_led(ucr);
 
        mutex_unlock(&ucr->dev_mutex);
+       pm_runtime_put(sdmmc_dev(host));
 }
 #endif
 
index 1f54fd8755c8e026fd8fb99f7fdb1cbc154acc87..7123ef96ed18523c88553146035103f3517bd372 100644 (file)
@@ -346,7 +346,8 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
        struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
        u32 data;
 
-       if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
+       if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE ||
+                       reg == SDHCI_INT_STATUS)) {
                if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) {
                        /*
                         * Clear and then set D3CD bit to avoid missing the
@@ -555,6 +556,25 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
        esdhc_clrset_le(host, 0xffff, val, reg);
 }
 
+static u8 esdhc_readb_le(struct sdhci_host *host, int reg)
+{
+       u8 ret;
+       u32 val;
+
+       switch (reg) {
+       case SDHCI_HOST_CONTROL:
+               val = readl(host->ioaddr + reg);
+
+               ret = val & SDHCI_CTRL_LED;
+               ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK;
+               ret |= (val & ESDHC_CTRL_4BITBUS);
+               ret |= (val & ESDHC_CTRL_8BITBUS) << 3;
+               return ret;
+       }
+
+       return readb(host->ioaddr + reg);
+}
+
 static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -947,6 +967,7 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl_le,
        .read_w = esdhc_readw_le,
+       .read_b = esdhc_readb_le,
        .write_l = esdhc_writel_le,
        .write_w = esdhc_writew_le,
        .write_b = esdhc_writeb_le,
index 8ef44a2a2fd94b6572e0cc5feda1efd0b698f7a6..90ed2e12d345d4ee91f6088aecac306897e2c266 100644 (file)
@@ -647,6 +647,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        if (msm_host->pwr_irq < 0) {
                dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n",
                        msm_host->pwr_irq);
+               ret = msm_host->pwr_irq;
                goto clk_disable;
        }
 
index da8e40af6f85e82143bb222f38d5663a2dbf1766..410a55b1c25fe5f2ef32ff8f2d26c4c3286f4b71 100644 (file)
@@ -250,7 +250,7 @@ static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
        writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
 }
 
-void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
+static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
 {
        u8 ctrl;
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -265,6 +265,28 @@ void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
        }
 }
 
+static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
+                                      struct mmc_ios *ios)
+{
+       switch (ios->signal_voltage) {
+       case MMC_SIGNAL_VOLTAGE_180:
+               /*
+                * Plese don't switch to 1V8 as arasan,5.1 doesn't
+                * actually refer to this setting to indicate the
+                * signal voltage and the state machine will be broken
+                * actually if we force to enable 1V8. That's something
+                * like broken quirk but we could work around here.
+                */
+               return 0;
+       case MMC_SIGNAL_VOLTAGE_330:
+       case MMC_SIGNAL_VOLTAGE_120:
+               /* We don't support 3V3 and 1V2 */
+               break;
+       }
+
+       return -EINVAL;
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
        .set_clock = sdhci_arasan_set_clock,
        .get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -661,6 +683,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 
                host->mmc_host_ops.hs400_enhanced_strobe =
                                        sdhci_arasan_hs400_enhanced_strobe;
+               host->mmc_host_ops.start_signal_voltage_switch =
+                                       sdhci_arasan_voltage_switch;
        }
 
        ret = sdhci_add_host(host);
index fb71c866eacc7028918e1abb667b230e784a47f4..1bb11e4a9fe53f7e01eb81bb87482f6bd96a56f1 100644 (file)
@@ -66,6 +66,20 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
                        return ret;
                }
        }
+       /*
+        * The DAT[3:0] line signal levels and the CMD line signal level are
+        * not compatible with standard SDHC register. The line signal levels
+        * DAT[7:0] are at bits 31:24 and the command line signal level is at
+        * bit 23. All other bits are the same as in the standard SDHC
+        * register.
+        */
+       if (spec_reg == SDHCI_PRESENT_STATE) {
+               ret = value & 0x000fffff;
+               ret |= (value >> 4) & SDHCI_DATA_LVL_MASK;
+               ret |= (value << 1) & SDHCI_CMD_LVL;
+               return ret;
+       }
+
        ret = value;
        return ret;
 }
index 72a1f1f5180a9cc12f5bdc7fffaa03685500f6e0..1d9e00a00e9fc986eb0bb01ff55a0966f03f7d5c 100644 (file)
 #include "sdhci-pci.h"
 #include "sdhci-pci-o2micro.h"
 
+static int sdhci_pci_enable_dma(struct sdhci_host *host);
+static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width);
+static void sdhci_pci_hw_reset(struct sdhci_host *host);
+static int sdhci_pci_select_drive_strength(struct sdhci_host *host,
+                                          struct mmc_card *card,
+                                          unsigned int max_dtr, int host_drv,
+                                          int card_drv, int *drv_type);
+
 /*****************************************************************************\
  *                                                                           *
  * Hardware specific quirk handling                                          *
@@ -390,6 +398,45 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
        return 0;
 }
 
+#define SDHCI_INTEL_PWR_TIMEOUT_CNT    20
+#define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100
+
+static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
+                                 unsigned short vdd)
+{
+       int cntr;
+       u8 reg;
+
+       sdhci_set_power(host, mode, vdd);
+
+       if (mode == MMC_POWER_OFF)
+               return;
+
+       /*
+        * Bus power might not enable after D3 -> D0 transition due to the
+        * present state not yet having propagated. Retry for up to 2ms.
+        */
+       for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) {
+               reg = sdhci_readb(host, SDHCI_POWER_CONTROL);
+               if (reg & SDHCI_POWER_ON)
+                       break;
+               udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY);
+               reg |= SDHCI_POWER_ON;
+               sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       }
+}
+
+static const struct sdhci_ops sdhci_intel_byt_ops = {
+       .set_clock              = sdhci_set_clock,
+       .set_power              = sdhci_intel_set_power,
+       .enable_dma             = sdhci_pci_enable_dma,
+       .set_bus_width          = sdhci_pci_set_bus_width,
+       .reset                  = sdhci_reset,
+       .set_uhs_signaling      = sdhci_set_uhs_signaling,
+       .hw_reset               = sdhci_pci_hw_reset,
+       .select_drive_strength  = sdhci_pci_select_drive_strength,
+};
+
 static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
        .allow_runtime_pm = true,
        .probe_slot     = byt_emmc_probe_slot,
@@ -397,6 +444,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
        .quirks2        = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
                          SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
                          SDHCI_QUIRK2_STOP_WITH_TC,
+       .ops            = &sdhci_intel_byt_ops,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
@@ -405,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
                        SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
        .allow_runtime_pm = true,
        .probe_slot     = byt_sdio_probe_slot,
+       .ops            = &sdhci_intel_byt_ops,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
@@ -415,6 +464,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
        .allow_runtime_pm = true,
        .own_cd_for_runtime_pm = true,
        .probe_slot     = byt_sd_probe_slot,
+       .ops            = &sdhci_intel_byt_ops,
 };
 
 /* Define Host controllers for Intel Merrifield platform */
@@ -1648,7 +1698,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
        }
 
        host->hw_name = "PCI";
-       host->ops = &sdhci_pci_ops;
+       host->ops = chip->fixes && chip->fixes->ops ?
+                   chip->fixes->ops :
+                   &sdhci_pci_ops;
        host->quirks = chip->quirks;
        host->quirks2 = chip->quirks2;
 
index 9c7c08b9322387f7914024ed404055ed7ba158cb..6bccf56bc5fff654d203ead074a6a53ae0409623 100644 (file)
@@ -65,6 +65,8 @@ struct sdhci_pci_fixes {
 
        int                     (*suspend) (struct sdhci_pci_chip *);
        int                     (*resume) (struct sdhci_pci_chip *);
+
+       const struct sdhci_ops  *ops;
 };
 
 struct sdhci_pci_slot {
index dd1938d341f7ae2af1de80bfa4f39678b865441d..d0f5c05fbc195fcf568d482efa0c5a41a0754a44 100644 (file)
@@ -315,7 +315,7 @@ static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
        struct mmc_host *mmc = host->mmc;
        u8 pwr = host->pwr;
 
-       sdhci_set_power(host, mode, vdd);
+       sdhci_set_power_noreg(host, mode, vdd);
 
        if (host->pwr == pwr)
                return;
index 48055666c6557a98286dd6d07118c82a218f5c76..42ef3ebb1d8cf9d57f30e48d21c3a5250aea16ea 100644 (file)
@@ -687,7 +687,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
                         * host->clock is in Hz.  target_timeout is in us.
                         * Hence, us = 1000000 * cycles / Hz.  Round up.
                         */
-                       val = 1000000 * data->timeout_clks;
+                       val = 1000000ULL * data->timeout_clks;
                        if (do_div(val, host->clock))
                                target_timeout++;
                        target_timeout += val;
@@ -1077,6 +1077,10 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        /* Initially, a command has no error */
        cmd->error = 0;
 
+       if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
+           cmd->opcode == MMC_STOP_TRANSMISSION)
+               cmd->flags |= MMC_RSP_BUSY;
+
        /* Wait max 10 ms */
        timeout = 10;
 
@@ -1390,8 +1394,8 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 }
 
-void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
-                    unsigned short vdd)
+void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
+                          unsigned short vdd)
 {
        u8 pwr = 0;
 
@@ -1455,20 +1459,17 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                        mdelay(10);
        }
 }
-EXPORT_SYMBOL_GPL(sdhci_set_power);
+EXPORT_SYMBOL_GPL(sdhci_set_power_noreg);
 
-static void __sdhci_set_power(struct sdhci_host *host, unsigned char mode,
-                             unsigned short vdd)
+void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+                    unsigned short vdd)
 {
-       struct mmc_host *mmc = host->mmc;
-
-       if (host->ops->set_power)
-               host->ops->set_power(host, mode, vdd);
-       else if (!IS_ERR(mmc->supply.vmmc))
-               sdhci_set_power_reg(host, mode, vdd);
+       if (IS_ERR(host->mmc->supply.vmmc))
+               sdhci_set_power_noreg(host, mode, vdd);
        else
-               sdhci_set_power(host, mode, vdd);
+               sdhci_set_power_reg(host, mode, vdd);
 }
+EXPORT_SYMBOL_GPL(sdhci_set_power);
 
 /*****************************************************************************\
  *                                                                           *
@@ -1609,7 +1610,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                }
        }
 
-       __sdhci_set_power(host, ios->power_mode, ios->vdd);
+       if (host->ops->set_power)
+               host->ops->set_power(host, ios->power_mode, ios->vdd);
+       else
+               sdhci_set_power(host, ios->power_mode, ios->vdd);
 
        if (host->ops->platform_send_init_74_clocks)
                host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -2082,6 +2086,10 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
                if (!host->tuning_done) {
                        pr_info(DRIVER_NAME ": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock\n");
+
+                       sdhci_do_reset(host, SDHCI_RESET_CMD);
+                       sdhci_do_reset(host, SDHCI_RESET_DATA);
+
                        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        ctrl &= ~SDHCI_CTRL_TUNED_CLK;
                        ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
@@ -2282,10 +2290,8 @@ static bool sdhci_request_done(struct sdhci_host *host)
 
        for (i = 0; i < SDHCI_MAX_MRQS; i++) {
                mrq = host->mrqs_done[i];
-               if (mrq) {
-                       host->mrqs_done[i] = NULL;
+               if (mrq)
                        break;
-               }
        }
 
        if (!mrq) {
@@ -2316,6 +2322,17 @@ static bool sdhci_request_done(struct sdhci_host *host)
         * upon error conditions.
         */
        if (sdhci_needs_reset(host, mrq)) {
+               /*
+                * Do not finish until command and data lines are available for
+                * reset. Note there can only be one other mrq, so it cannot
+                * also be in mrqs_done, otherwise host->cmd and host->data_cmd
+                * would both be null.
+                */
+               if (host->cmd || host->data_cmd) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       return true;
+               }
+
                /* Some controllers need this kick or reset won't work here */
                if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
                        /* This is to force an update */
@@ -2323,10 +2340,8 @@ static bool sdhci_request_done(struct sdhci_host *host)
 
                /* Spec says we should do both at the same time, but Ricoh
                   controllers do not like that. */
-               if (!host->cmd)
-                       sdhci_do_reset(host, SDHCI_RESET_CMD);
-               if (!host->data_cmd)
-                       sdhci_do_reset(host, SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD);
+               sdhci_do_reset(host, SDHCI_RESET_DATA);
 
                host->pending_reset = false;
        }
@@ -2334,6 +2349,8 @@ static bool sdhci_request_done(struct sdhci_host *host)
        if (!sdhci_has_requests(host))
                sdhci_led_deactivate(host);
 
+       host->mrqs_done[i] = NULL;
+
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 
@@ -2409,7 +2426,7 @@ static void sdhci_timeout_data_timer(unsigned long data)
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 {
        if (!host->cmd) {
                /*
@@ -2453,11 +2470,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
                return;
        }
 
-       if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
-           !(host->cmd->flags & MMC_RSP_BUSY) && !host->data &&
-           host->cmd->opcode == MMC_STOP_TRANSMISSION)
-               *mask &= ~SDHCI_INT_DATA_END;
-
        if (intmask & SDHCI_INT_RESPONSE)
                sdhci_finish_command(host);
 }
@@ -2513,9 +2525,6 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
        if (!host->data) {
                struct mmc_command *data_cmd = host->data_cmd;
 
-               if (data_cmd)
-                       host->data_cmd = NULL;
-
                /*
                 * The "data complete" interrupt is also used to
                 * indicate that a busy state has ended. See comment
@@ -2523,11 +2532,13 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                 */
                if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) {
                        if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+                               host->data_cmd = NULL;
                                data_cmd->error = -ETIMEDOUT;
                                sdhci_finish_mrq(host, data_cmd->mrq);
                                return;
                        }
                        if (intmask & SDHCI_INT_DATA_END) {
+                               host->data_cmd = NULL;
                                /*
                                 * Some cards handle busy-end interrupt
                                 * before the command completed, so make
@@ -2680,8 +2691,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                }
 
                if (intmask & SDHCI_INT_CMD_MASK)
-                       sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK,
-                                     &intmask);
+                       sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
 
                if (intmask & SDHCI_INT_DATA_MASK)
                        sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
@@ -2914,6 +2924,10 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
                spin_unlock_irqrestore(&host->lock, flags);
        }
 
+       if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
+           mmc->ops->hs400_enhanced_strobe)
+               mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+
        spin_lock_irqsave(&host->lock, flags);
 
        host->runtime_suspended = false;
index c722cd23205cd2306ed42feb20f17173493d049e..2570455b219a469c1669ff4d3f9935ca89e37c6f 100644 (file)
@@ -73,6 +73,7 @@
 #define  SDHCI_DATA_LVL_MASK   0x00F00000
 #define   SDHCI_DATA_LVL_SHIFT 20
 #define   SDHCI_DATA_0_LVL_MASK        0x00100000
+#define  SDHCI_CMD_LVL         0x01000000
 
 #define SDHCI_HOST_CONTROL     0x28
 #define  SDHCI_CTRL_LED                0x01
@@ -683,6 +684,8 @@ u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
 void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
 void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                     unsigned short vdd);
+void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
+                          unsigned short vdd);
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
 void sdhci_reset(struct sdhci_host *host, u8 mask);
 void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
index 0f68a99fc4ad0135b5852327be6b7177b6fb5cfd..141bd70a49c2c5c888d290b724b2ed6a59af2216 100644 (file)
@@ -161,7 +161,7 @@ int gpmi_init(struct gpmi_nand_data *this)
 
        ret = gpmi_enable_clk(this);
        if (ret)
-               goto err_out;
+               return ret;
        ret = gpmi_reset_block(r->gpmi_regs, false);
        if (ret)
                goto err_out;
@@ -197,6 +197,7 @@ int gpmi_init(struct gpmi_nand_data *this)
        gpmi_disable_clk(this);
        return 0;
 err_out:
+       gpmi_disable_clk(this);
        return ret;
 }
 
@@ -270,7 +271,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
 
        ret = gpmi_enable_clk(this);
        if (ret)
-               goto err_out;
+               return ret;
 
        /*
        * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
@@ -308,6 +309,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        gpmi_disable_clk(this);
        return 0;
 err_out:
+       gpmi_disable_clk(this);
        return ret;
 }
 
index d54f666417e183c4f148826db042931b5d81f47c..dbf256217b3eb75a0486a0f2ec8774c05f793fe8 100644 (file)
@@ -86,6 +86,8 @@ struct mtk_ecc {
        struct completion done;
        struct mutex lock;
        u32 sectors;
+
+       u8 eccdata[112];
 };
 
 static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
@@ -366,9 +368,8 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
                   u8 *data, u32 bytes)
 {
        dma_addr_t addr;
-       u8 *p;
-       u32 len, i, val;
-       int ret = 0;
+       u32 len;
+       int ret;
 
        addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
        ret = dma_mapping_error(ecc->dev, addr);
@@ -393,14 +394,12 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
 
        /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
        len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
-       p = data + bytes;
 
-       /* write the parity bytes generated by the ECC back to the OOB region */
-       for (i = 0; i < len; i++) {
-               if ((i % 4) == 0)
-                       val = readl(ecc->regs + ECC_ENCPAR(i / 4));
-               p[i] = (val >> ((i % 4) * 8)) & 0xff;
-       }
+       /* write the parity bytes generated by the ECC back to temp buffer */
+       __ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4));
+
+       /* copy into possibly unaligned OOB region with actual length */
+       memcpy(data + bytes, ecc->eccdata, len);
 timeout:
 
        dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
index e5718e5ecf925868012eb0332c43d071f32a727f..3bde96a3f7bfd5b8f066fc56af91fb1983279cdf 100644 (file)
@@ -1095,10 +1095,11 @@ static void nand_release_data_interface(struct nand_chip *chip)
 /**
  * nand_reset - Reset and initialize a NAND device
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Returns 0 for success or negative error code otherwise
  */
-int nand_reset(struct nand_chip *chip)
+int nand_reset(struct nand_chip *chip, int chipnr)
 {
        struct mtd_info *mtd = nand_to_mtd(chip);
        int ret;
@@ -1107,9 +1108,17 @@ int nand_reset(struct nand_chip *chip)
        if (ret)
                return ret;
 
+       /*
+        * The CS line has to be released before we can apply the new NAND
+        * interface settings, hence this weird ->select_chip() dance.
+        */
+       chip->select_chip(mtd, chipnr);
        chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+       chip->select_chip(mtd, -1);
 
+       chip->select_chip(mtd, chipnr);
        ret = nand_setup_data_interface(chip);
+       chip->select_chip(mtd, -1);
        if (ret)
                return ret;
 
@@ -1185,8 +1194,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        /* Shift to get chip number */
        chipnr = ofs >> chip->chip_shift;
 
-       chip->select_chip(mtd, chipnr);
-
        /*
         * Reset the chip.
         * If we want to check the WP through READ STATUS and check the bit 7
@@ -1194,7 +1201,9 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
         * some operation can also clear the bit 7 of status register
         * eg. erase/program a locked block
         */
-       nand_reset(chip);
+       nand_reset(chip, chipnr);
+
+       chip->select_chip(mtd, chipnr);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -1244,8 +1253,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        /* Shift to get chip number */
        chipnr = ofs >> chip->chip_shift;
 
-       chip->select_chip(mtd, chipnr);
-
        /*
         * Reset the chip.
         * If we want to check the WP through READ STATUS and check the bit 7
@@ -1253,7 +1260,9 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
         * some operation can also clear the bit 7 of status register
         * eg. erase/program a locked block
         */
-       nand_reset(chip);
+       nand_reset(chip, chipnr);
+
+       chip->select_chip(mtd, chipnr);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -2940,10 +2949,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        }
 
        chipnr = (int)(to >> chip->chip_shift);
-       chip->select_chip(mtd, chipnr);
-
-       /* Shift to get page */
-       page = (int)(to >> chip->page_shift);
 
        /*
         * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
@@ -2951,7 +2956,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
         * if we don't do this. I have no clue why, but I seem to have 'fixed'
         * it in the doc2000 driver in August 1999.  dwmw2.
         */
-       nand_reset(chip);
+       nand_reset(chip, chipnr);
+
+       chip->select_chip(mtd, chipnr);
+
+       /* Shift to get page */
+       page = (int)(to >> chip->page_shift);
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
@@ -3984,14 +3994,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        int i, maf_idx;
        u8 id_data[8];
 
-       /* Select the device */
-       chip->select_chip(mtd, 0);
-
        /*
         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
         * after power-up.
         */
-       nand_reset(chip);
+       nand_reset(chip, 0);
+
+       /* Select the device */
+       chip->select_chip(mtd, 0);
 
        /* Send the command for reading device ID */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -4329,17 +4339,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                return PTR_ERR(type);
        }
 
+       /* Initialize the ->data_interface field. */
        ret = nand_init_data_interface(chip);
        if (ret)
                return ret;
 
+       /*
+        * Setup the data interface correctly on the chip and controller side.
+        * This explicit call to nand_setup_data_interface() is only required
+        * for the first die, because nand_reset() has been called before
+        * ->data_interface and ->default_onfi_timing_mode were set.
+        * For the other dies, nand_reset() will automatically switch to the
+        * best mode for us.
+        */
+       ret = nand_setup_data_interface(chip);
+       if (ret)
+               return ret;
+
        chip->select_chip(mtd, -1);
 
        /* Check for a chip array */
        for (i = 1; i < maxchips; i++) {
-               chip->select_chip(mtd, i);
                /* See comment in nand_get_flash_type for reset */
-               nand_reset(chip);
+               nand_reset(chip, i);
+
+               chip->select_chip(mtd, i);
                /* Send the command for reading device ID */
                chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                /* Read manufacturer and device IDs */
index 95c4048a371e87b6f5517b01109b19db85cedc56..388e46be6ad92805f2a6633da6960d8c56b1b837 100644 (file)
@@ -741,6 +741,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
                goto out_put;
        }
 
+       vid_hdr = ubi_get_vid_hdr(vidb);
        ubi_assert(vid_hdr->vol_type == UBI_VID_DYNAMIC);
 
        mutex_lock(&ubi->buf_mutex);
index d6384d9657885c31c01e8fa1a5a2ed82530b0891..c1f5c29e458ef86305376fa7b404f9c5b8e05681 100644 (file)
@@ -287,7 +287,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai,
 
                /* new_aeb is newer */
                if (cmp_res & 1) {
-                       victim = ubi_alloc_aeb(ai, aeb->ec, aeb->pnum);
+                       victim = ubi_alloc_aeb(ai, aeb->pnum, aeb->ec);
                        if (!victim)
                                return -ENOMEM;
 
@@ -707,11 +707,11 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
                             fmvhdr->vol_type,
                             be32_to_cpu(fmvhdr->last_eb_bytes));
 
-               if (!av)
-                       goto fail_bad;
-               if (PTR_ERR(av) == -EINVAL) {
-                       ubi_err(ubi, "volume (ID %i) already exists",
-                               fmvhdr->vol_id);
+               if (IS_ERR(av)) {
+                       if (PTR_ERR(av) == -EEXIST)
+                               ubi_err(ubi, "volume (ID %i) already exists",
+                                       fmvhdr->vol_id);
+
                        goto fail_bad;
                }
 
index 3eb7430dffbf1378df8c4c9c40f92a99e06e879d..f8ff25c8ee2e46122083de6f45816648f60c0370 100644 (file)
@@ -142,6 +142,9 @@ struct plx_pci_card {
 #define CTI_PCI_VENDOR_ID              0x12c4
 #define CTI_PCI_DEVICE_ID_CRG001       0x0900
 
+#define MOXA_PCI_VENDOR_ID             0x1393
+#define MOXA_PCI_DEVICE_ID             0x0100
+
 static void plx_pci_reset_common(struct pci_dev *pdev);
 static void plx9056_pci_reset_common(struct pci_dev *pdev);
 static void plx_pci_reset_marathon_pci(struct pci_dev *pdev);
@@ -258,6 +261,14 @@ static struct plx_pci_card_info plx_pci_card_info_elcus = {
        /* based on PLX9030 */
 };
 
+static struct plx_pci_card_info plx_pci_card_info_moxa = {
+       "MOXA", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {0, 0x00, 0x00}, { {0, 0x00, 0x80}, {1, 0x00, 0x80} },
+       &plx_pci_reset_common
+        /* based on PLX9052 */
+};
+
 static const struct pci_device_id plx_pci_tbl[] = {
        {
                /* Adlink PCI-7841/cPCI-7841 */
@@ -357,6 +368,13 @@ static const struct pci_device_id plx_pci_tbl[] = {
                0, 0,
                (kernel_ulong_t)&plx_pci_card_info_elcus
        },
+       {
+               /* moxa */
+               MOXA_PCI_VENDOR_ID, MOXA_PCI_DEVICE_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_moxa
+       },
        { 0,}
 };
 MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
index e8fc4952c6b074f80a2af132d2bc161e7fd3d8c7..2147678f0225344f1f40ee4a42781f778cee588c 100644 (file)
@@ -43,11 +43,22 @@ struct __packed pucan_command {
        u16     args[3];
 };
 
+#define PUCAN_TSLOW_BRP_BITS           10
+#define PUCAN_TSLOW_TSGEG1_BITS                8
+#define PUCAN_TSLOW_TSGEG2_BITS                7
+#define PUCAN_TSLOW_SJW_BITS           7
+
+#define PUCAN_TSLOW_BRP_MASK           ((1 << PUCAN_TSLOW_BRP_BITS) - 1)
+#define PUCAN_TSLOW_TSEG1_MASK         ((1 << PUCAN_TSLOW_TSGEG1_BITS) - 1)
+#define PUCAN_TSLOW_TSEG2_MASK         ((1 << PUCAN_TSLOW_TSGEG2_BITS) - 1)
+#define PUCAN_TSLOW_SJW_MASK           ((1 << PUCAN_TSLOW_SJW_BITS) - 1)
+
 /* uCAN TIMING_SLOW command fields */
-#define PUCAN_TSLOW_SJW_T(s, t)                (((s) & 0xf) | ((!!(t)) << 7))
-#define PUCAN_TSLOW_TSEG2(t)           ((t) & 0xf)
-#define PUCAN_TSLOW_TSEG1(t)           ((t) & 0x3f)
-#define PUCAN_TSLOW_BRP(b)             ((b) & 0x3ff)
+#define PUCAN_TSLOW_SJW_T(s, t)                (((s) & PUCAN_TSLOW_SJW_MASK) | \
+                                                               ((!!(t)) << 7))
+#define PUCAN_TSLOW_TSEG2(t)           ((t) & PUCAN_TSLOW_TSEG2_MASK)
+#define PUCAN_TSLOW_TSEG1(t)           ((t) & PUCAN_TSLOW_TSEG1_MASK)
+#define PUCAN_TSLOW_BRP(b)             ((b) & PUCAN_TSLOW_BRP_MASK)
 
 struct __packed pucan_timing_slow {
        __le16  opcode_channel;
@@ -60,11 +71,21 @@ struct __packed pucan_timing_slow {
        __le16  brp;            /* BaudRate Prescaler */
 };
 
+#define PUCAN_TFAST_BRP_BITS           10
+#define PUCAN_TFAST_TSGEG1_BITS                5
+#define PUCAN_TFAST_TSGEG2_BITS                4
+#define PUCAN_TFAST_SJW_BITS           4
+
+#define PUCAN_TFAST_BRP_MASK           ((1 << PUCAN_TFAST_BRP_BITS) - 1)
+#define PUCAN_TFAST_TSEG1_MASK         ((1 << PUCAN_TFAST_TSGEG1_BITS) - 1)
+#define PUCAN_TFAST_TSEG2_MASK         ((1 << PUCAN_TFAST_TSGEG2_BITS) - 1)
+#define PUCAN_TFAST_SJW_MASK           ((1 << PUCAN_TFAST_SJW_BITS) - 1)
+
 /* uCAN TIMING_FAST command fields */
-#define PUCAN_TFAST_SJW(s)             ((s) & 0x3)
-#define PUCAN_TFAST_TSEG2(t)           ((t) & 0x7)
-#define PUCAN_TFAST_TSEG1(t)           ((t) & 0xf)
-#define PUCAN_TFAST_BRP(b)             ((b) & 0x3ff)
+#define PUCAN_TFAST_SJW(s)             ((s) & PUCAN_TFAST_SJW_MASK)
+#define PUCAN_TFAST_TSEG2(t)           ((t) & PUCAN_TFAST_TSEG2_MASK)
+#define PUCAN_TFAST_TSEG1(t)           ((t) & PUCAN_TFAST_TSEG1_MASK)
+#define PUCAN_TFAST_BRP(b)             ((b) & PUCAN_TFAST_BRP_MASK)
 
 struct __packed pucan_timing_fast {
        __le16  opcode_channel;
index c06382cdfdfee4d736ef9b86eb2ef33104a62b92..0b0302af3bd2dc3da893ed120afa028d21b219da 100644 (file)
@@ -39,6 +39,7 @@ static struct usb_device_id peak_usb_table[] = {
        {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)},
        {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID)},
        {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID)},
+       {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBX6_PRODUCT_ID)},
        {} /* Terminating entry */
 };
 
@@ -50,6 +51,7 @@ static const struct peak_usb_adapter *const peak_usb_adapters_list[] = {
        &pcan_usb_pro,
        &pcan_usb_fd,
        &pcan_usb_pro_fd,
+       &pcan_usb_x6,
 };
 
 /*
@@ -868,23 +870,25 @@ lbl_free_candev:
 static void peak_usb_disconnect(struct usb_interface *intf)
 {
        struct peak_usb_device *dev;
+       struct peak_usb_device *dev_prev_siblings;
 
        /* unregister as many netdev devices as siblings */
-       for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) {
+       for (dev = usb_get_intfdata(intf); dev; dev = dev_prev_siblings) {
                struct net_device *netdev = dev->netdev;
                char name[IFNAMSIZ];
 
+               dev_prev_siblings = dev->prev_siblings;
                dev->state &= ~PCAN_USB_STATE_CONNECTED;
                strncpy(name, netdev->name, IFNAMSIZ);
 
                unregister_netdev(netdev);
-               free_candev(netdev);
 
                kfree(dev->cmd_buf);
                dev->next_siblings = NULL;
                if (dev->adapter->dev_free)
                        dev->adapter->dev_free(dev);
 
+               free_candev(netdev);
                dev_info(&intf->dev, "%s removed\n", name);
        }
 
index 506fe506c9d37fcb212196457d9db37f3a46cb2a..3cbfb069893d5ce1d2da16969426433240ad4ce6 100644 (file)
@@ -27,6 +27,7 @@
 #define PCAN_USBPRO_PRODUCT_ID         0x000d
 #define PCAN_USBPROFD_PRODUCT_ID       0x0011
 #define PCAN_USBFD_PRODUCT_ID          0x0012
+#define PCAN_USBX6_PRODUCT_ID          0x0014
 
 #define PCAN_USB_DRIVER_NAME           "peak_usb"
 
@@ -90,6 +91,7 @@ extern const struct peak_usb_adapter pcan_usb;
 extern const struct peak_usb_adapter pcan_usb_pro;
 extern const struct peak_usb_adapter pcan_usb_fd;
 extern const struct peak_usb_adapter pcan_usb_pro_fd;
+extern const struct peak_usb_adapter pcan_usb_x6;
 
 struct peak_time_ref {
        struct timeval tv_host_0, tv_host;
index ce44a033f63bb1456d44139b003c14cecb35b7e9..304732550f0a628a7fa9ae9c94e67113d9a869a0 100644 (file)
@@ -993,24 +993,24 @@ static void pcan_usb_fd_free(struct peak_usb_device *dev)
 static const struct can_bittiming_const pcan_usb_fd_const = {
        .name = "pcan_usb_fd",
        .tseg1_min = 1,
-       .tseg1_max = 64,
+       .tseg1_max = (1 << PUCAN_TSLOW_TSGEG1_BITS),
        .tseg2_min = 1,
-       .tseg2_max = 16,
-       .sjw_max = 16,
+       .tseg2_max = (1 << PUCAN_TSLOW_TSGEG2_BITS),
+       .sjw_max = (1 << PUCAN_TSLOW_SJW_BITS),
        .brp_min = 1,
-       .brp_max = 1024,
+       .brp_max = (1 << PUCAN_TSLOW_BRP_BITS),
        .brp_inc = 1,
 };
 
 static const struct can_bittiming_const pcan_usb_fd_data_const = {
        .name = "pcan_usb_fd",
        .tseg1_min = 1,
-       .tseg1_max = 16,
+       .tseg1_max = (1 << PUCAN_TFAST_TSGEG1_BITS),
        .tseg2_min = 1,
-       .tseg2_max = 8,
-       .sjw_max = 4,
+       .tseg2_max = (1 << PUCAN_TFAST_TSGEG2_BITS),
+       .sjw_max = (1 << PUCAN_TFAST_SJW_BITS),
        .brp_min = 1,
-       .brp_max = 1024,
+       .brp_max = (1 << PUCAN_TFAST_BRP_BITS),
        .brp_inc = 1,
 };
 
@@ -1065,24 +1065,24 @@ const struct peak_usb_adapter pcan_usb_fd = {
 static const struct can_bittiming_const pcan_usb_pro_fd_const = {
        .name = "pcan_usb_pro_fd",
        .tseg1_min = 1,
-       .tseg1_max = 64,
+       .tseg1_max = (1 << PUCAN_TSLOW_TSGEG1_BITS),
        .tseg2_min = 1,
-       .tseg2_max = 16,
-       .sjw_max = 16,
+       .tseg2_max = (1 << PUCAN_TSLOW_TSGEG2_BITS),
+       .sjw_max = (1 << PUCAN_TSLOW_SJW_BITS),
        .brp_min = 1,
-       .brp_max = 1024,
+       .brp_max = (1 << PUCAN_TSLOW_BRP_BITS),
        .brp_inc = 1,
 };
 
 static const struct can_bittiming_const pcan_usb_pro_fd_data_const = {
        .name = "pcan_usb_pro_fd",
        .tseg1_min = 1,
-       .tseg1_max = 16,
+       .tseg1_max = (1 << PUCAN_TFAST_TSGEG1_BITS),
        .tseg2_min = 1,
-       .tseg2_max = 8,
-       .sjw_max = 4,
+       .tseg2_max = (1 << PUCAN_TFAST_TSGEG2_BITS),
+       .sjw_max = (1 << PUCAN_TFAST_SJW_BITS),
        .brp_min = 1,
-       .brp_max = 1024,
+       .brp_max = (1 << PUCAN_TFAST_BRP_BITS),
        .brp_inc = 1,
 };
 
@@ -1132,3 +1132,75 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
 
        .do_get_berr_counter = pcan_usb_fd_get_berr_counter,
 };
+
+/* describes the PCAN-USB X6 adapter */
+static const struct can_bittiming_const pcan_usb_x6_const = {
+       .name = "pcan_usb_x6",
+       .tseg1_min = 1,
+       .tseg1_max = (1 << PUCAN_TSLOW_TSGEG1_BITS),
+       .tseg2_min = 1,
+       .tseg2_max = (1 << PUCAN_TSLOW_TSGEG2_BITS),
+       .sjw_max = (1 << PUCAN_TSLOW_SJW_BITS),
+       .brp_min = 1,
+       .brp_max = (1 << PUCAN_TSLOW_BRP_BITS),
+       .brp_inc = 1,
+};
+
+static const struct can_bittiming_const pcan_usb_x6_data_const = {
+       .name = "pcan_usb_x6",
+       .tseg1_min = 1,
+       .tseg1_max = (1 << PUCAN_TFAST_TSGEG1_BITS),
+       .tseg2_min = 1,
+       .tseg2_max = (1 << PUCAN_TFAST_TSGEG2_BITS),
+       .sjw_max = (1 << PUCAN_TFAST_SJW_BITS),
+       .brp_min = 1,
+       .brp_max = (1 << PUCAN_TFAST_BRP_BITS),
+       .brp_inc = 1,
+};
+
+const struct peak_usb_adapter pcan_usb_x6 = {
+       .name = "PCAN-USB X6",
+       .device_id = PCAN_USBX6_PRODUCT_ID,
+       .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
+       .ctrlmode_supported = CAN_CTRLMODE_FD |
+                       CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY,
+       .clock = {
+               .freq = PCAN_UFD_CRYSTAL_HZ,
+       },
+       .bittiming_const = &pcan_usb_x6_const,
+       .data_bittiming_const = &pcan_usb_x6_data_const,
+
+       /* size of device private data */
+       .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
+
+       /* timestamps usage */
+       .ts_used_bits = 32,
+       .ts_period = 1000000, /* calibration period in ts. */
+       .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
+       .us_per_ts_shift = 0,
+
+       /* give here messages in/out endpoints */
+       .ep_msg_in = PCAN_USBPRO_EP_MSGIN,
+       .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0, PCAN_USBPRO_EP_MSGOUT_1},
+
+       /* size of rx/tx usb buffers */
+       .rx_buffer_size = PCAN_UFD_RX_BUFFER_SIZE,
+       .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE,
+
+       /* device callbacks */
+       .intf_probe = pcan_usb_pro_probe,       /* same as PCAN-USB Pro */
+       .dev_init = pcan_usb_fd_init,
+
+       .dev_exit = pcan_usb_fd_exit,
+       .dev_free = pcan_usb_fd_free,
+       .dev_set_bus = pcan_usb_fd_set_bus,
+       .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow,
+       .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast,
+       .dev_decode_buf = pcan_usb_fd_decode_buf,
+       .dev_start = pcan_usb_fd_start,
+       .dev_stop = pcan_usb_fd_stop,
+       .dev_restart_async = pcan_usb_fd_restart_async,
+       .dev_encode_msg = pcan_usb_fd_encode_msg,
+
+       .do_get_berr_counter = pcan_usb_fd_get_berr_counter,
+};
index 7717b19dc806bf1532ac263525a35ce643c7cdd6..947adda3397d64ce9e86f5cfe8e300b4e8650827 100644 (file)
@@ -962,9 +962,10 @@ static void b53_vlan_add(struct dsa_switch *ds, int port,
 
                vl->members |= BIT(port) | BIT(cpu_port);
                if (untagged)
-                       vl->untag |= BIT(port) | BIT(cpu_port);
+                       vl->untag |= BIT(port);
                else
-                       vl->untag &= ~(BIT(port) | BIT(cpu_port));
+                       vl->untag &= ~BIT(port);
+               vl->untag &= ~BIT(cpu_port);
 
                b53_set_vlan_entry(dev, vid, vl);
                b53_fast_age_vlan(dev, vid);
@@ -973,8 +974,6 @@ static void b53_vlan_add(struct dsa_switch *ds, int port,
        if (pvid) {
                b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port),
                            vlan->vid_end);
-               b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(cpu_port),
-                           vlan->vid_end);
                b53_fast_age_vlan(dev, vid);
        }
 }
@@ -984,7 +983,6 @@ static int b53_vlan_del(struct dsa_switch *ds, int port,
 {
        struct b53_device *dev = ds->priv;
        bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
-       unsigned int cpu_port = dev->cpu_port;
        struct b53_vlan *vl;
        u16 vid;
        u16 pvid;
@@ -997,8 +995,6 @@ static int b53_vlan_del(struct dsa_switch *ds, int port,
                b53_get_vlan_entry(dev, vid, vl);
 
                vl->members &= ~BIT(port);
-               if ((vl->members & BIT(cpu_port)) == BIT(cpu_port))
-                       vl->members = 0;
 
                if (pvid == vid) {
                        if (is5325(dev) || is5365(dev))
@@ -1007,18 +1003,14 @@ static int b53_vlan_del(struct dsa_switch *ds, int port,
                                pvid = 0;
                }
 
-               if (untagged) {
+               if (untagged)
                        vl->untag &= ~(BIT(port));
-                       if ((vl->untag & BIT(cpu_port)) == BIT(cpu_port))
-                               vl->untag = 0;
-               }
 
                b53_set_vlan_entry(dev, vid, vl);
                b53_fast_age_vlan(dev, vid);
        }
 
        b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), pvid);
-       b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(cpu_port), pvid);
        b53_fast_age_vlan(dev, pvid);
 
        return 0;
index 76fb8552c9d93a6d3e2c424ee3ad0ef55be04adf..ef63d24fef8149a1fd26614933a5ea4dd5dae86f 100644 (file)
@@ -256,6 +256,7 @@ static const struct of_device_id b53_mmap_of_table[] = {
        { .compatible = "brcm,bcm63xx-switch" },
        { /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, b53_mmap_of_table);
 
 static struct platform_driver b53_mmap_driver = {
        .probe = b53_mmap_probe,
index e218887f18b79e352435416d8d9b3047cf52ae66..9ec33b51a0edad879701bef79d6c8f250d778b91 100644 (file)
@@ -588,6 +588,7 @@ static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
                                   struct phy_device *phydev)
 {
        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+       struct ethtool_eee *p = &priv->port_sts[port].eee;
        u32 id_mode_dis = 0, port_mode;
        const char *str = NULL;
        u32 reg;
@@ -662,6 +663,9 @@ force_link:
                reg |= DUPLX_MODE;
 
        core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
+
+       if (!phydev->is_pseudo_fixed_link)
+               p->eee_enabled = bcm_sf2_eee_init(ds, port, phydev);
 }
 
 static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
@@ -1133,6 +1137,20 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void bcm_sf2_sw_shutdown(struct platform_device *pdev)
+{
+       struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);
+
+       /* For a kernel about to be kexec'd we want to keep the GPHY on for a
+        * successful MDIO bus scan to occur. If we did turn off the GPHY
+        * before (e.g: port_disable), this will also power it back on.
+        *
+        * Do not rely on kexec_in_progress, just power the PHY on.
+        */
+       if (priv->hw_params.num_gphy == 1)
+               bcm_sf2_gphy_enable_set(priv->dev->ds, true);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int bcm_sf2_suspend(struct device *dev)
 {
@@ -1158,10 +1176,12 @@ static const struct of_device_id bcm_sf2_of_match[] = {
        { .compatible = "brcm,bcm7445-switch-v4.0" },
        { /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, bcm_sf2_of_match);
 
 static struct platform_driver bcm_sf2_driver = {
        .probe  = bcm_sf2_sw_probe,
        .remove = bcm_sf2_sw_remove,
+       .shutdown = bcm_sf2_sw_shutdown,
        .driver = {
                .name = "brcm-sf2",
                .of_match_table = bcm_sf2_of_match,
index bda31f308cc2a0b028273298345b5d43b03908b6..a0eee72186957211329609cd357f5c140278c412 100644 (file)
@@ -400,12 +400,6 @@ static int tse_rx(struct altera_tse_private *priv, int limit)
 
                skb_put(skb, pktlength);
 
-               /* make cache consistent with receive packet buffer */
-               dma_sync_single_for_cpu(priv->device,
-                                       priv->rx_ring[entry].dma_addr,
-                                       priv->rx_ring[entry].len,
-                                       DMA_FROM_DEVICE);
-
                dma_unmap_single(priv->device, priv->rx_ring[entry].dma_addr,
                                 priv->rx_ring[entry].len, DMA_FROM_DEVICE);
 
@@ -469,7 +463,6 @@ static int tse_tx_complete(struct altera_tse_private *priv)
 
        if (unlikely(netif_queue_stopped(priv->dev) &&
                     tse_tx_avail(priv) > TSE_TX_THRESH(priv))) {
-               netif_tx_lock(priv->dev);
                if (netif_queue_stopped(priv->dev) &&
                    tse_tx_avail(priv) > TSE_TX_THRESH(priv)) {
                        if (netif_msg_tx_done(priv))
@@ -477,7 +470,6 @@ static int tse_tx_complete(struct altera_tse_private *priv)
                                           __func__);
                        netif_wake_queue(priv->dev);
                }
-               netif_tx_unlock(priv->dev);
        }
 
        spin_unlock(&priv->tx_lock);
@@ -592,10 +584,6 @@ static int tse_start_xmit(struct sk_buff *skb, struct net_device *dev)
        buffer->dma_addr = dma_addr;
        buffer->len = nopaged_len;
 
-       /* Push data out of the cache hierarchy into main memory */
-       dma_sync_single_for_device(priv->device, buffer->dma_addr,
-                                  buffer->len, DMA_TO_DEVICE);
-
        priv->dmaops->tx_buffer(priv, buffer);
 
        skb_tx_timestamp(skb);
@@ -819,6 +807,8 @@ static int init_phy(struct net_device *dev)
 
        if (!phydev) {
                netdev_err(dev, "Could not find the PHY\n");
+               if (fixed_link)
+                       of_phy_deregister_fixed_link(priv->device->of_node);
                return -ENODEV;
        }
 
@@ -1545,10 +1535,15 @@ err_free_netdev:
 static int altera_tse_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
+       struct altera_tse_private *priv = netdev_priv(ndev);
 
-       if (ndev->phydev)
+       if (ndev->phydev) {
                phy_disconnect(ndev->phydev);
 
+               if (of_phy_is_fixed_link(priv->device->of_node))
+                       of_phy_deregister_fixed_link(priv->device->of_node);
+       }
+
        platform_set_drvdata(pdev, NULL);
        altera_tse_mdio_destroy(ndev);
        unregister_netdev(ndev);
index 9de078819aa676525d4fae65a6a47e3df448dc1e..4f76351782005557a31ecd5f2997f7e8c888e78c 100644 (file)
@@ -829,7 +829,7 @@ static int xgbe_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int xgbe_suspend(struct device *dev)
 {
        struct net_device *netdev = dev_get_drvdata(dev);
@@ -874,7 +874,7 @@ static int xgbe_resume(struct device *dev)
 
        return ret;
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgbe_acpi_match[] = {
index c481f104a8febc4acacf223ad2c3fd5f4147ef41..5390ae89136c6b7870c5d915655854707192b0d5 100644 (file)
@@ -204,17 +204,6 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
        return num_msgs;
 }
 
-static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
-{
-       u32 data = 0x7777;
-
-       xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
-       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
-       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
-       xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
-       xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
-}
-
 void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
                            struct xgene_enet_pdata *pdata,
                            enum xgene_enet_err_code status)
@@ -929,5 +918,4 @@ struct xgene_ring_ops xgene_ring1_ops = {
        .clear = xgene_enet_clear_ring,
        .wr_cmd = xgene_enet_wr_cmd,
        .len = xgene_enet_ring_len,
-       .coalesce = xgene_enet_setup_coalescing,
 };
index 8456337a237db91a837593570b3a659e66835d69..06e598c8bc16e5618c110fcfbd5b183b464f86c3 100644 (file)
@@ -55,8 +55,10 @@ enum xgene_enet_rm {
 #define PREFETCH_BUF_EN                BIT(21)
 #define CSR_RING_ID_BUF                0x000c
 #define CSR_PBM_COAL           0x0014
+#define CSR_PBM_CTICK0         0x0018
 #define CSR_PBM_CTICK1         0x001c
 #define CSR_PBM_CTICK2         0x0020
+#define CSR_PBM_CTICK3         0x0024
 #define CSR_THRESHOLD0_SET1    0x0030
 #define CSR_THRESHOLD1_SET1    0x0034
 #define CSR_RING_NE_INT_MODE   0x017c
index 429f18fc5503ddede288ff0203068a56ce9df3a8..8158d4698734dd76be6475d38d7f17800517362b 100644 (file)
@@ -1188,7 +1188,8 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
                tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
        }
 
-       pdata->ring_ops->coalesce(pdata->tx_ring[0]);
+       if (pdata->ring_ops->coalesce)
+               pdata->ring_ops->coalesce(pdata->tx_ring[0]);
        pdata->tx_qcnt_hi = pdata->tx_ring[0]->slots - 128;
 
        return 0;
index 2b76732add5dbbd6d25fd6fd6e1b887c317d167a..af51dd5844ceeeee5d7aa9bfd5a81979c24f7d56 100644 (file)
@@ -30,7 +30,7 @@ static void xgene_enet_ring_init(struct xgene_enet_desc_ring *ring)
                ring_cfg[0] |= SET_VAL(X2_INTLINE, ring->id & RING_BUFNUM_MASK);
                ring_cfg[3] |= SET_BIT(X2_DEQINTEN);
        }
-       ring_cfg[0] |= SET_VAL(X2_CFGCRID, 1);
+       ring_cfg[0] |= SET_VAL(X2_CFGCRID, 2);
 
        addr >>= 8;
        ring_cfg[2] |= QCOHERENT | SET_VAL(RINGADDRL, addr);
@@ -192,13 +192,15 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
 
 static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
 {
-       u32 data = 0x7777;
+       u32 data = 0x77777777;
 
        xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
+       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK0, data);
        xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
-       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
-       xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
-       xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
+       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data);
+       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK3, data);
+       xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x08);
+       xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x10);
 }
 
 struct xgene_ring_ops xgene_ring2_ops = {
index b0da9693f28a130a65e59a007548c773fa422e7f..be865b4dada2c65e7089ca4147ef47758698dc51 100644 (file)
@@ -460,7 +460,7 @@ static void arc_emac_set_rx_mode(struct net_device *ndev)
                if (ndev->flags & IFF_ALLMULTI) {
                        arc_reg_set(priv, R_LAFL, ~0);
                        arc_reg_set(priv, R_LAFH, ~0);
-               } else {
+               } else if (ndev->flags & IFF_MULTICAST) {
                        struct netdev_hw_addr *ha;
                        unsigned int filter[2] = { 0, 0 };
                        int bit;
@@ -472,6 +472,9 @@ static void arc_emac_set_rx_mode(struct net_device *ndev)
 
                        arc_reg_set(priv, R_LAFL, filter[0]);
                        arc_reg_set(priv, R_LAFH, filter[1]);
+               } else {
+                       arc_reg_set(priv, R_LAFL, 0);
+                       arc_reg_set(priv, R_LAFH, 0);
                }
        }
 }
@@ -764,8 +767,6 @@ int arc_emac_probe(struct net_device *ndev, int interface)
        ndev->netdev_ops = &arc_emac_netdev_ops;
        ndev->ethtool_ops = &arc_emac_ethtool_ops;
        ndev->watchdog_timeo = TX_TIMEOUT;
-       /* FIXME :: no multicast support yet */
-       ndev->flags &= ~IFF_MULTICAST;
 
        priv = netdev_priv(ndev);
        priv->dev = dev;
index b047fd607b83bc796684ceb945ccc715ebdb1c80..e078d8da978c189ccf411c903fadcdb3434ab8b9 100644 (file)
@@ -1358,6 +1358,7 @@ static const struct of_device_id nb8800_dt_ids[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(of, nb8800_dt_ids);
 
 static int nb8800_probe(struct platform_device *pdev)
 {
@@ -1465,12 +1466,12 @@ static int nb8800_probe(struct platform_device *pdev)
 
        ret = nb8800_hw_init(dev);
        if (ret)
-               goto err_free_bus;
+               goto err_deregister_fixed_link;
 
        if (ops && ops->init) {
                ret = ops->init(dev);
                if (ret)
-                       goto err_free_bus;
+                       goto err_deregister_fixed_link;
        }
 
        dev->netdev_ops = &nb8800_netdev_ops;
@@ -1503,6 +1504,9 @@ static int nb8800_probe(struct platform_device *pdev)
 
 err_free_dma:
        nb8800_dma_free(dev);
+err_deregister_fixed_link:
+       if (of_phy_is_fixed_link(pdev->dev.of_node))
+               of_phy_deregister_fixed_link(pdev->dev.of_node);
 err_free_bus:
        of_node_put(priv->phy_node);
        mdiobus_unregister(bus);
@@ -1520,6 +1524,8 @@ static int nb8800_remove(struct platform_device *pdev)
        struct nb8800_priv *priv = netdev_priv(ndev);
 
        unregister_netdev(ndev);
+       if (of_phy_is_fixed_link(pdev->dev.of_node))
+               of_phy_deregister_fixed_link(pdev->dev.of_node);
        of_node_put(priv->phy_node);
 
        mdiobus_unregister(priv->mii_bus);
index ae364c74baf3f4eaa8a3af6cb42b0b91ccda6805..537090952c45494bfedbd5ae7b374ad54af46681 100644 (file)
@@ -1126,7 +1126,8 @@ out_freeirq:
        free_irq(dev->irq, dev);
 
 out_phy_disconnect:
-       phy_disconnect(phydev);
+       if (priv->has_phy)
+               phy_disconnect(phydev);
 
        return ret;
 }
index c3354b9941d1cc733aa7999eaf6fd1f8d4244af1..25d1eb4933d0b8b28dc53d07344eb6a47a263893 100644 (file)
@@ -1755,13 +1755,13 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        if (priv->irq0 <= 0 || priv->irq1 <= 0) {
                dev_err(&pdev->dev, "invalid interrupts\n");
                ret = -EINVAL;
-               goto err;
+               goto err_free_netdev;
        }
 
        priv->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(priv->base)) {
                ret = PTR_ERR(priv->base);
-               goto err;
+               goto err_free_netdev;
        }
 
        priv->netdev = dev;
@@ -1779,7 +1779,7 @@ static int bcm_sysport_probe(struct platform_device *pdev)
                ret = of_phy_register_fixed_link(dn);
                if (ret) {
                        dev_err(&pdev->dev, "failed to register fixed PHY\n");
-                       goto err;
+                       goto err_free_netdev;
                }
 
                priv->phy_dn = dn;
@@ -1821,7 +1821,7 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        ret = register_netdev(dev);
        if (ret) {
                dev_err(&pdev->dev, "failed to register net_device\n");
-               goto err;
+               goto err_deregister_fixed_link;
        }
 
        priv->rev = topctrl_readl(priv, REV_CNTL) & REV_MASK;
@@ -1832,7 +1832,11 @@ static int bcm_sysport_probe(struct platform_device *pdev)
                 priv->base, priv->irq0, priv->irq1, txq, rxq);
 
        return 0;
-err:
+
+err_deregister_fixed_link:
+       if (of_phy_is_fixed_link(dn))
+               of_phy_deregister_fixed_link(dn);
+err_free_netdev:
        free_netdev(dev);
        return ret;
 }
@@ -1840,11 +1844,14 @@ err:
 static int bcm_sysport_remove(struct platform_device *pdev)
 {
        struct net_device *dev = dev_get_drvdata(&pdev->dev);
+       struct device_node *dn = pdev->dev.of_node;
 
        /* Not much to do, ndo_close has been called
         * and we use managed allocations
         */
        unregister_netdev(dev);
+       if (of_phy_is_fixed_link(dn))
+               of_phy_deregister_fixed_link(dn);
        free_netdev(dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
index 856379cbb40265ed8e4e34a9e23ded1a32ecda0b..49f4cafe543806ed51ed8690b271e309c5609b9f 100644 (file)
@@ -307,6 +307,10 @@ static void bgmac_dma_rx_enable(struct bgmac *bgmac,
        u32 ctl;
 
        ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL);
+
+       /* preserve ONLY bits 16-17 from current hardware value */
+       ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
+
        if (bgmac->feature_flags & BGMAC_FEAT_RX_MASK_SETUP) {
                ctl &= ~BGMAC_DMA_RX_BL_MASK;
                ctl |= BGMAC_DMA_RX_BL_128 << BGMAC_DMA_RX_BL_SHIFT;
@@ -317,7 +321,6 @@ static void bgmac_dma_rx_enable(struct bgmac *bgmac,
                ctl &= ~BGMAC_DMA_RX_PT_MASK;
                ctl |= BGMAC_DMA_RX_PT_1 << BGMAC_DMA_RX_PT_SHIFT;
        }
-       ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
        ctl |= BGMAC_DMA_RX_ENABLE;
        ctl |= BGMAC_DMA_RX_PARITY_DISABLE;
        ctl |= BGMAC_DMA_RX_OVERFLOW_CONT;
@@ -1046,9 +1049,9 @@ static void bgmac_enable(struct bgmac *bgmac)
 
        mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
                BGMAC_DS_MM_SHIFT;
-       if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) || mode != 0)
+       if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0)
                bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
-       if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST && mode == 2)
+       if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) && mode == 2)
                bgmac_cco_ctl_maskset(bgmac, 1, ~0,
                                      BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
 
@@ -1449,7 +1452,7 @@ static int bgmac_phy_connect(struct bgmac *bgmac)
        phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
                              PHY_INTERFACE_MODE_MII);
        if (IS_ERR(phy_dev)) {
-               dev_err(bgmac->dev, "PHY connecton failed\n");
+               dev_err(bgmac->dev, "PHY connection failed\n");
                return PTR_ERR(phy_dev);
        }
 
index 27f11a5d5fe2783b13722175006ad3d10cde367c..1f7034d739b00a02b88beb0ec8ddde875a824882 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/firmware.h>
 #include <linux/log2.h>
 #include <linux/aer.h>
+#include <linux/crash_dump.h>
 
 #if IS_ENABLED(CONFIG_CNIC)
 #define BCM_CNIC 1
@@ -271,22 +272,25 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
 static u32
 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
 {
+       unsigned long flags;
        u32 val;
 
-       spin_lock_bh(&bp->indirect_lock);
+       spin_lock_irqsave(&bp->indirect_lock, flags);
        BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
        val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW);
-       spin_unlock_bh(&bp->indirect_lock);
+       spin_unlock_irqrestore(&bp->indirect_lock, flags);
        return val;
 }
 
 static void
 bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
 {
-       spin_lock_bh(&bp->indirect_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bp->indirect_lock, flags);
        BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
        BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
-       spin_unlock_bh(&bp->indirect_lock);
+       spin_unlock_irqrestore(&bp->indirect_lock, flags);
 }
 
 static void
@@ -304,8 +308,10 @@ bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
 static void
 bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
 {
+       unsigned long flags;
+
        offset += cid_addr;
-       spin_lock_bh(&bp->indirect_lock);
+       spin_lock_irqsave(&bp->indirect_lock, flags);
        if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
                int i;
 
@@ -322,7 +328,7 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
                BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset);
                BNX2_WR(bp, BNX2_CTX_DATA, val);
        }
-       spin_unlock_bh(&bp->indirect_lock);
+       spin_unlock_irqrestore(&bp->indirect_lock, flags);
 }
 
 #ifdef BCM_CNIC
@@ -4759,15 +4765,16 @@ bnx2_setup_msix_tbl(struct bnx2 *bp)
        BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
 }
 
-static int
-bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
+static void
+bnx2_wait_dma_complete(struct bnx2 *bp)
 {
        u32 val;
-       int i, rc = 0;
-       u8 old_port;
+       int i;
 
-       /* Wait for the current PCI transaction to complete before
-        * issuing a reset. */
+       /*
+        * Wait for the current PCI transaction to complete before
+        * issuing a reset.
+        */
        if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
            (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
                BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
@@ -4791,6 +4798,21 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
                }
        }
 
+       return;
+}
+
+
+static int
+bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
+{
+       u32 val;
+       int i, rc = 0;
+       u8 old_port;
+
+       /* Wait for the current PCI transaction to complete before
+        * issuing a reset. */
+       bnx2_wait_dma_complete(bp);
+
        /* Wait for the firmware to tell us it is ok to issue a reset. */
        bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
 
@@ -6356,6 +6378,10 @@ bnx2_open(struct net_device *dev)
        struct bnx2 *bp = netdev_priv(dev);
        int rc;
 
+       rc = bnx2_request_firmware(bp);
+       if (rc < 0)
+               goto out;
+
        netif_carrier_off(dev);
 
        bnx2_disable_int(bp);
@@ -6424,6 +6450,7 @@ open_err:
        bnx2_free_irq(bp);
        bnx2_free_mem(bp);
        bnx2_del_napi(bp);
+       bnx2_release_firmware(bp);
        goto out;
 }
 
@@ -8570,12 +8597,15 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_drvdata(pdev, dev);
 
-       rc = bnx2_request_firmware(bp);
-       if (rc < 0)
-               goto error;
-
+       /*
+        * In-flight DMA from 1st kernel could continue going in kdump kernel.
+        * New io-page table has been created before bnx2 does reset at open stage.
+        * We have to wait for the in-flight DMA to complete to avoid it look up
+        * into the newly created io-page table.
+        */
+       if (is_kdump_kernel())
+               bnx2_wait_dma_complete(bp);
 
-       bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
        memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);
 
        dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
@@ -8608,7 +8638,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 
 error:
-       bnx2_release_firmware(bp);
        pci_iounmap(pdev, bp->regview);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
index 85a7800bfc128e56b5a3886cba65b707ed5db57b..5f19427c7b278b99ee34a20b4d854e1d1293578b 100644 (file)
@@ -1872,8 +1872,16 @@ static void bnx2x_get_ringparam(struct net_device *dev,
 
        ering->rx_max_pending = MAX_RX_AVAIL;
 
+       /* If size isn't already set, we give an estimation of the number
+        * of buffers we'll have. We're neglecting some possible conditions
+        * [we couldn't know for certain at this point if number of queues
+        * might shrink] but the number would be correct for the likely
+        * scenario.
+        */
        if (bp->rx_ring_size)
                ering->rx_pending = bp->rx_ring_size;
+       else if (BNX2X_NUM_RX_QUEUES(bp))
+               ering->rx_pending = MAX_RX_AVAIL / BNX2X_NUM_RX_QUEUES(bp);
        else
                ering->rx_pending = MAX_RX_AVAIL;
 
index 20fe6a8c35c16af3dc00b2e130f2f0e58115b13a..4febe60eadc2ef57e592943ef6b3515a22bd3111 100644 (file)
@@ -10138,7 +10138,7 @@ static void __bnx2x_add_udp_port(struct bnx2x *bp, u16 port,
 {
        struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];
 
-       if (!netif_running(bp->dev) || !IS_PF(bp))
+       if (!netif_running(bp->dev) || !IS_PF(bp) || CHIP_IS_E1x(bp))
                return;
 
        if (udp_port->count && udp_port->dst_port == port) {
@@ -10163,7 +10163,7 @@ static void __bnx2x_del_udp_port(struct bnx2x *bp, u16 port,
 {
        struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];
 
-       if (!IS_PF(bp))
+       if (!IS_PF(bp) || CHIP_IS_E1x(bp))
                return;
 
        if (!udp_port->count || udp_port->dst_port != port) {
@@ -13505,6 +13505,7 @@ static int bnx2x_init_firmware(struct bnx2x *bp)
 
        /* Initialize the pointers to the init arrays */
        /* Blob */
+       rc = -ENOMEM;
        BNX2X_ALLOC_AND_SET(init_data, request_firmware_exit, be32_to_cpu_n);
 
        /* Opcodes */
@@ -15241,7 +15242,7 @@ static void bnx2x_init_cyclecounter(struct bnx2x *bp)
        memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter));
        bp->cyclecounter.read = bnx2x_cyclecounter_read;
        bp->cyclecounter.mask = CYCLECOUNTER_MASK(64);
-       bp->cyclecounter.shift = 1;
+       bp->cyclecounter.shift = 0;
        bp->cyclecounter.mult = 1;
 }
 
index a9f9f3738022a708b0020659d30d2aafacc12cf6..f08a20b921e7a66f7738c65becb9993523452634 100644 (file)
@@ -1811,6 +1811,9 @@ static int bnxt_busy_poll(struct napi_struct *napi)
        if (atomic_read(&bp->intr_sem) != 0)
                return LL_FLUSH_FAILED;
 
+       if (!bp->link_info.link_up)
+               return LL_FLUSH_FAILED;
+
        if (!bnxt_lock_poll(bnapi))
                return LL_FLUSH_BUSY;
 
@@ -3210,11 +3213,17 @@ static int bnxt_hwrm_tunnel_dst_port_alloc(struct bnxt *bp, __be16 port,
                goto err_out;
        }
 
-       if (tunnel_type & TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN)
+       switch (tunnel_type) {
+       case TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN:
                bp->vxlan_fw_dst_port_id = resp->tunnel_dst_port_id;
-
-       else if (tunnel_type & TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GENEVE)
+               break;
+       case TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GENEVE:
                bp->nge_fw_dst_port_id = resp->tunnel_dst_port_id;
+               break;
+       default:
+               break;
+       }
+
 err_out:
        mutex_unlock(&bp->hwrm_cmd_lock);
        return rc;
@@ -4111,7 +4120,7 @@ static int bnxt_hwrm_stat_ctx_alloc(struct bnxt *bp)
                bp->grp_info[i].fw_stats_ctx = cpr->hw_stats_ctx_id;
        }
        mutex_unlock(&bp->hwrm_cmd_lock);
-       return 0;
+       return rc;
 }
 
 static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
@@ -4934,6 +4943,10 @@ static void bnxt_del_napi(struct bnxt *bp)
                napi_hash_del(&bnapi->napi);
                netif_napi_del(&bnapi->napi);
        }
+       /* We called napi_hash_del() before netif_napi_del(), we need
+        * to respect an RCU grace period before freeing napi structures.
+        */
+       synchronize_net();
 }
 
 static void bnxt_init_napi(struct bnxt *bp)
@@ -6309,6 +6322,7 @@ static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
                         struct tc_to_netdev *ntc)
 {
        struct bnxt *bp = netdev_priv(dev);
+       bool sh = false;
        u8 tc;
 
        if (ntc->type != TC_SETUP_MQPRIO)
@@ -6325,12 +6339,11 @@ static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
        if (netdev_get_num_tc(dev) == tc)
                return 0;
 
+       if (bp->flags & BNXT_FLAG_SHARED_RINGS)
+               sh = true;
+
        if (tc) {
                int max_rx_rings, max_tx_rings, rc;
-               bool sh = false;
-
-               if (bp->flags & BNXT_FLAG_SHARED_RINGS)
-                       sh = true;
 
                rc = bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, sh);
                if (rc || bp->tx_nr_rings_per_tc * tc > max_tx_rings)
@@ -6348,7 +6361,8 @@ static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
                bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
                netdev_reset_tc(dev);
        }
-       bp->cp_nr_rings = max_t(int, bp->tx_nr_rings, bp->rx_nr_rings);
+       bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
+                              bp->tx_nr_rings + bp->rx_nr_rings;
        bp->num_stat_ctxs = bp->cp_nr_rings;
 
        if (netif_running(bp->dev))
index ec6cd18842c3cf15d6fa215fee145b693a04466e..60e2af8678bdc2bcd71f5015d35ca8599268b8c5 100644 (file)
@@ -774,8 +774,8 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
 
                if (vf->flags & BNXT_VF_LINK_UP) {
                        /* if physical link is down, force link up on VF */
-                       if (phy_qcfg_resp.link ==
-                           PORT_PHY_QCFG_RESP_LINK_NO_LINK) {
+                       if (phy_qcfg_resp.link !=
+                           PORT_PHY_QCFG_RESP_LINK_LINK) {
                                phy_qcfg_resp.link =
                                        PORT_PHY_QCFG_RESP_LINK_LINK;
                                phy_qcfg_resp.link_speed = cpu_to_le16(
index 4464bc5db9347654806831b5e0f1d6042a3f8c75..a4e60e56c14f73495d588f059e815f09d7a9e243 100644 (file)
@@ -1172,6 +1172,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
                                          struct bcmgenet_tx_ring *ring)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct device *kdev = &priv->pdev->dev;
        struct enet_cb *tx_cb_ptr;
        struct netdev_queue *txq;
        unsigned int pkts_compl = 0;
@@ -1199,13 +1200,13 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
                if (tx_cb_ptr->skb) {
                        pkts_compl++;
                        bytes_compl += GENET_CB(tx_cb_ptr->skb)->bytes_sent;
-                       dma_unmap_single(&dev->dev,
+                       dma_unmap_single(kdev,
                                         dma_unmap_addr(tx_cb_ptr, dma_addr),
                                         dma_unmap_len(tx_cb_ptr, dma_len),
                                         DMA_TO_DEVICE);
                        bcmgenet_free_cb(tx_cb_ptr);
                } else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) {
-                       dma_unmap_page(&dev->dev,
+                       dma_unmap_page(kdev,
                                       dma_unmap_addr(tx_cb_ptr, dma_addr),
                                       dma_unmap_len(tx_cb_ptr, dma_len),
                                       DMA_TO_DEVICE);
@@ -1775,6 +1776,7 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
 
 static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
 {
+       struct device *kdev = &priv->pdev->dev;
        struct enet_cb *cb;
        int i;
 
@@ -1782,7 +1784,7 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
                cb = &priv->rx_cbs[i];
 
                if (dma_unmap_addr(cb, dma_addr)) {
-                       dma_unmap_single(&priv->dev->dev,
+                       dma_unmap_single(kdev,
                                         dma_unmap_addr(cb, dma_addr),
                                         priv->rx_buf_len, DMA_FROM_DEVICE);
                        dma_unmap_addr_set(cb, dma_addr, 0);
index 457c3bc8cfff49654b45e879495e5cbfa88428d6..e87607621e62a076104d67046a10603305d66ecf 100644 (file)
@@ -542,8 +542,10 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
        /* Make sure we initialize MoCA PHYs with a link down */
        if (phy_mode == PHY_INTERFACE_MODE_MOCA) {
                phydev = of_phy_find_device(dn);
-               if (phydev)
+               if (phydev) {
                        phydev->link = 0;
+                       put_device(&phydev->mdio.dev);
+               }
        }
 
        return 0;
@@ -625,6 +627,7 @@ static int bcmgenet_mii_bus_init(struct bcmgenet_priv *priv)
 int bcmgenet_mii_init(struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct device_node *dn = priv->pdev->dev.of_node;
        int ret;
 
        ret = bcmgenet_mii_alloc(priv);
@@ -638,6 +641,8 @@ int bcmgenet_mii_init(struct net_device *dev)
        return 0;
 
 out:
+       if (of_phy_is_fixed_link(dn))
+               of_phy_deregister_fixed_link(dn);
        of_node_put(priv->phy_dn);
        mdiobus_unregister(priv->mii_bus);
        mdiobus_free(priv->mii_bus);
@@ -647,7 +652,10 @@ out:
 void bcmgenet_mii_exit(struct net_device *dev)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct device_node *dn = priv->pdev->dev.of_node;
 
+       if (of_phy_is_fixed_link(dn))
+               of_phy_deregister_fixed_link(dn);
        of_node_put(priv->phy_dn);
        mdiobus_unregister(priv->mii_bus);
        mdiobus_free(priv->mii_bus);
index f9df4b5ae90e091d7bd440e16d87ef404ab1ba80..f42f672b0e7eab91e3cc90dece31bf691eb02bc8 100644 (file)
@@ -177,6 +177,7 @@ bnad_txcmpl_process(struct bnad *bnad, struct bna_tcb *tcb)
                return 0;
 
        hw_cons = *(tcb->hw_consumer_index);
+       rmb();
        cons = tcb->consumer_index;
        q_depth = tcb->q_depth;
 
@@ -3094,7 +3095,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        BNA_QE_INDX_INC(prod, q_depth);
        tcb->producer_index = prod;
 
-       smp_mb();
+       wmb();
 
        if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)))
                return NETDEV_TX_OK;
@@ -3102,7 +3103,6 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        skb_tx_timestamp(skb);
 
        bna_txq_prod_indx_doorbell(tcb);
-       smp_mb();
 
        return NETDEV_TX_OK;
 }
index b32444a3ed79d311fc4047aa10eabc5f630b66cb..ec09fcece711dc326dca2c63db8440e193eb2b31 100644 (file)
@@ -975,6 +975,7 @@ static inline void macb_init_rx_ring(struct macb *bp)
                addr += bp->rx_buffer_size;
        }
        bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
+       bp->rx_tail = 0;
 }
 
 static int macb_rx(struct macb *bp, int budget)
@@ -1156,6 +1157,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                if (status & MACB_BIT(RXUBR)) {
                        ctrl = macb_readl(bp, NCR);
                        macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));
+                       wmb();
                        macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
 
                        if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
@@ -1616,8 +1618,6 @@ static void macb_init_rings(struct macb *bp)
        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;
 }
 
 static void macb_reset_hw(struct macb *bp)
@@ -2673,6 +2673,12 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
                lp->skb_length = skb->len;
                lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len,
                                                        DMA_TO_DEVICE);
+               if (dma_mapping_error(NULL, lp->skb_physaddr)) {
+                       dev_kfree_skb_any(skb);
+                       dev->stats.tx_dropped++;
+                       netdev_err(dev, "%s: DMA mapping error\n", __func__);
+                       return NETDEV_TX_OK;
+               }
 
                /* Set address of the data in the Transmit Address register */
                macb_writel(lp, TAR, lp->skb_physaddr);
@@ -2764,6 +2770,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
        if (intstatus & MACB_BIT(RXUBR)) {
                ctl = macb_readl(lp, NCR);
                macb_writel(lp, NCR, ctl & ~MACB_BIT(RE));
+               wmb();
                macb_writel(lp, NCR, ctl | MACB_BIT(RE));
        }
 
index 30426109711cf4ebec9f1cc28fed75e7961d79a0..86bd93ce2ea30fc66f1c9c63fdf5a5d6209013a2 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Min/Max packet size */
 #define        NIC_HW_MIN_FRS                  64
-#define        NIC_HW_MAX_FRS                  9200 /* 9216 max packet including FCS */
+#define        NIC_HW_MAX_FRS                  9190 /* Excluding L2 header and FCS */
 
 /* Max pkinds */
 #define        NIC_MAX_PKIND                   16
@@ -178,11 +178,11 @@ enum tx_stats_reg_offset {
 
 struct nicvf_hw_stats {
        u64 rx_bytes;
+       u64 rx_frames;
        u64 rx_ucast_frames;
        u64 rx_bcast_frames;
        u64 rx_mcast_frames;
-       u64 rx_fcs_errors;
-       u64 rx_l2_errors;
+       u64 rx_drops;
        u64 rx_drop_red;
        u64 rx_drop_red_bytes;
        u64 rx_drop_overrun;
@@ -191,6 +191,19 @@ struct nicvf_hw_stats {
        u64 rx_drop_mcast;
        u64 rx_drop_l3_bcast;
        u64 rx_drop_l3_mcast;
+       u64 rx_fcs_errors;
+       u64 rx_l2_errors;
+
+       u64 tx_bytes;
+       u64 tx_frames;
+       u64 tx_ucast_frames;
+       u64 tx_bcast_frames;
+       u64 tx_mcast_frames;
+       u64 tx_drops;
+};
+
+struct nicvf_drv_stats {
+       /* CQE Rx errs */
        u64 rx_bgx_truncated_pkts;
        u64 rx_jabber_errs;
        u64 rx_fcs_errs;
@@ -216,34 +229,30 @@ struct nicvf_hw_stats {
        u64 rx_l4_pclp;
        u64 rx_truncated_pkts;
 
-       u64 tx_bytes_ok;
-       u64 tx_ucast_frames_ok;
-       u64 tx_bcast_frames_ok;
-       u64 tx_mcast_frames_ok;
-       u64 tx_drops;
-};
-
-struct nicvf_drv_stats {
-       /* Rx */
-       u64 rx_frames_ok;
-       u64 rx_frames_64;
-       u64 rx_frames_127;
-       u64 rx_frames_255;
-       u64 rx_frames_511;
-       u64 rx_frames_1023;
-       u64 rx_frames_1518;
-       u64 rx_frames_jumbo;
-       u64 rx_drops;
-
+       /* CQE Tx errs */
+       u64 tx_desc_fault;
+       u64 tx_hdr_cons_err;
+       u64 tx_subdesc_err;
+       u64 tx_max_size_exceeded;
+       u64 tx_imm_size_oflow;
+       u64 tx_data_seq_err;
+       u64 tx_mem_seq_err;
+       u64 tx_lock_viol;
+       u64 tx_data_fault;
+       u64 tx_tstmp_conflict;
+       u64 tx_tstmp_timeout;
+       u64 tx_mem_fault;
+       u64 tx_csum_overlap;
+       u64 tx_csum_overflow;
+
+       /* driver debug stats */
        u64 rcv_buffer_alloc_failures;
-
-       /* Tx */
-       u64 tx_frames_ok;
-       u64 tx_drops;
        u64 tx_tso;
        u64 tx_timeout;
        u64 txq_stop;
        u64 txq_wake;
+
+       struct u64_stats_sync   syncp;
 };
 
 struct nicvf {
@@ -282,7 +291,6 @@ struct nicvf {
 
        u8                      node;
        u8                      cpi_alg;
-       u16                     mtu;
        bool                    link_up;
        u8                      duplex;
        u32                     speed;
@@ -298,7 +306,7 @@ struct nicvf {
 
        /* Stats */
        struct nicvf_hw_stats   hw_stats;
-       struct nicvf_drv_stats  drv_stats;
+       struct nicvf_drv_stats  __percpu *drv_stats;
        struct bgx_stats        bgx_stats;
 
        /* MSI-X  */
index 2bbf4cbf08b21f273100d589f6893eb2e04fd3b4..6677b96e1f3f6e033ac985847e3b65b27db17842 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 #include <linux/of.h>
+#include <linux/if_vlan.h>
 
 #include "nic_reg.h"
 #include "nic.h"
@@ -260,18 +261,31 @@ static void nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx)
 /* Update hardware min/max frame size */
 static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf)
 {
-       if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) {
-               dev_err(&nic->pdev->dev,
-                       "Invalid MTU setting from VF%d rejected, should be between %d and %d\n",
-                          vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS);
+       int bgx, lmac, lmac_cnt;
+       u64 lmac_credits;
+
+       if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS))
                return 1;
-       }
-       new_frs += ETH_HLEN;
-       if (new_frs <= nic->pkind.maxlen)
-               return 0;
 
-       nic->pkind.maxlen = new_frs;
-       nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(u64 *)&nic->pkind);
+       bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+       lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+       lmac += bgx * MAX_LMAC_PER_BGX;
+
+       new_frs += VLAN_ETH_HLEN + ETH_FCS_LEN + 4;
+
+       /* Update corresponding LMAC credits */
+       lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
+       lmac_credits = nic_reg_read(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8));
+       lmac_credits &= ~(0xFFFFFULL << 12);
+       lmac_credits |= (((((48 * 1024) / lmac_cnt) - new_frs) / 16) << 12);
+       nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credits);
+
+       /* Enforce MTU in HW
+        * This config is supported only from 88xx pass 2.0 onwards.
+        */
+       if (!pass1_silicon(nic->pdev))
+               nic_reg_write(nic,
+                             NIC_PF_LMAC_0_7_CFG2 + (lmac * 8), new_frs);
        return 0;
 }
 
@@ -464,7 +478,7 @@ static int nic_init_hw(struct nicpf *nic)
 
        /* PKIND configuration */
        nic->pkind.minlen = 0;
-       nic->pkind.maxlen = NIC_HW_MAX_FRS + ETH_HLEN;
+       nic->pkind.maxlen = NIC_HW_MAX_FRS + VLAN_ETH_HLEN + ETH_FCS_LEN + 4;
        nic->pkind.lenerr_en = 1;
        nic->pkind.rx_hdr = 0;
        nic->pkind.hdr_sl = 0;
@@ -837,6 +851,7 @@ static int nic_reset_stat_counters(struct nicpf *nic,
                        nic_reg_write(nic, reg_addr, 0);
                }
        }
+
        return 0;
 }
 
index edf779f5a227022df6069e267ef697ef05e784c8..80d46337cf29183a3a0911b0d94ff23ad08f3418 100644 (file)
 #define   NIC_PF_MPI_0_2047_CFG                        (0x210000)
 #define   NIC_PF_RSSI_0_4097_RQ                        (0x220000)
 #define   NIC_PF_LMAC_0_7_CFG                  (0x240000)
+#define   NIC_PF_LMAC_0_7_CFG2                 (0x240100)
 #define   NIC_PF_LMAC_0_7_SW_XOFF              (0x242000)
 #define   NIC_PF_LMAC_0_7_CREDIT               (0x244000)
 #define   NIC_PF_CHAN_0_255_TX_CFG             (0x400000)
index ad4fddb5542160b4512643cde5228f7a9d28b2e0..432bf6be57cb2ff596d43ec08f2ff0aa250d4b86 100644 (file)
@@ -36,11 +36,11 @@ struct nicvf_stat {
 
 static const struct nicvf_stat nicvf_hw_stats[] = {
        NICVF_HW_STAT(rx_bytes),
+       NICVF_HW_STAT(rx_frames),
        NICVF_HW_STAT(rx_ucast_frames),
        NICVF_HW_STAT(rx_bcast_frames),
        NICVF_HW_STAT(rx_mcast_frames),
-       NICVF_HW_STAT(rx_fcs_errors),
-       NICVF_HW_STAT(rx_l2_errors),
+       NICVF_HW_STAT(rx_drops),
        NICVF_HW_STAT(rx_drop_red),
        NICVF_HW_STAT(rx_drop_red_bytes),
        NICVF_HW_STAT(rx_drop_overrun),
@@ -49,50 +49,59 @@ static const struct nicvf_stat nicvf_hw_stats[] = {
        NICVF_HW_STAT(rx_drop_mcast),
        NICVF_HW_STAT(rx_drop_l3_bcast),
        NICVF_HW_STAT(rx_drop_l3_mcast),
-       NICVF_HW_STAT(rx_bgx_truncated_pkts),
-       NICVF_HW_STAT(rx_jabber_errs),
-       NICVF_HW_STAT(rx_fcs_errs),
-       NICVF_HW_STAT(rx_bgx_errs),
-       NICVF_HW_STAT(rx_prel2_errs),
-       NICVF_HW_STAT(rx_l2_hdr_malformed),
-       NICVF_HW_STAT(rx_oversize),
-       NICVF_HW_STAT(rx_undersize),
-       NICVF_HW_STAT(rx_l2_len_mismatch),
-       NICVF_HW_STAT(rx_l2_pclp),
-       NICVF_HW_STAT(rx_ip_ver_errs),
-       NICVF_HW_STAT(rx_ip_csum_errs),
-       NICVF_HW_STAT(rx_ip_hdr_malformed),
-       NICVF_HW_STAT(rx_ip_payload_malformed),
-       NICVF_HW_STAT(rx_ip_ttl_errs),
-       NICVF_HW_STAT(rx_l3_pclp),
-       NICVF_HW_STAT(rx_l4_malformed),
-       NICVF_HW_STAT(rx_l4_csum_errs),
-       NICVF_HW_STAT(rx_udp_len_errs),
-       NICVF_HW_STAT(rx_l4_port_errs),
-       NICVF_HW_STAT(rx_tcp_flag_errs),
-       NICVF_HW_STAT(rx_tcp_offset_errs),
-       NICVF_HW_STAT(rx_l4_pclp),
-       NICVF_HW_STAT(rx_truncated_pkts),
-       NICVF_HW_STAT(tx_bytes_ok),
-       NICVF_HW_STAT(tx_ucast_frames_ok),
-       NICVF_HW_STAT(tx_bcast_frames_ok),
-       NICVF_HW_STAT(tx_mcast_frames_ok),
+       NICVF_HW_STAT(rx_fcs_errors),
+       NICVF_HW_STAT(rx_l2_errors),
+       NICVF_HW_STAT(tx_bytes),
+       NICVF_HW_STAT(tx_frames),
+       NICVF_HW_STAT(tx_ucast_frames),
+       NICVF_HW_STAT(tx_bcast_frames),
+       NICVF_HW_STAT(tx_mcast_frames),
+       NICVF_HW_STAT(tx_drops),
 };
 
 static const struct nicvf_stat nicvf_drv_stats[] = {
-       NICVF_DRV_STAT(rx_frames_ok),
-       NICVF_DRV_STAT(rx_frames_64),
-       NICVF_DRV_STAT(rx_frames_127),
-       NICVF_DRV_STAT(rx_frames_255),
-       NICVF_DRV_STAT(rx_frames_511),
-       NICVF_DRV_STAT(rx_frames_1023),
-       NICVF_DRV_STAT(rx_frames_1518),
-       NICVF_DRV_STAT(rx_frames_jumbo),
-       NICVF_DRV_STAT(rx_drops),
+       NICVF_DRV_STAT(rx_bgx_truncated_pkts),
+       NICVF_DRV_STAT(rx_jabber_errs),
+       NICVF_DRV_STAT(rx_fcs_errs),
+       NICVF_DRV_STAT(rx_bgx_errs),
+       NICVF_DRV_STAT(rx_prel2_errs),
+       NICVF_DRV_STAT(rx_l2_hdr_malformed),
+       NICVF_DRV_STAT(rx_oversize),
+       NICVF_DRV_STAT(rx_undersize),
+       NICVF_DRV_STAT(rx_l2_len_mismatch),
+       NICVF_DRV_STAT(rx_l2_pclp),
+       NICVF_DRV_STAT(rx_ip_ver_errs),
+       NICVF_DRV_STAT(rx_ip_csum_errs),
+       NICVF_DRV_STAT(rx_ip_hdr_malformed),
+       NICVF_DRV_STAT(rx_ip_payload_malformed),
+       NICVF_DRV_STAT(rx_ip_ttl_errs),
+       NICVF_DRV_STAT(rx_l3_pclp),
+       NICVF_DRV_STAT(rx_l4_malformed),
+       NICVF_DRV_STAT(rx_l4_csum_errs),
+       NICVF_DRV_STAT(rx_udp_len_errs),
+       NICVF_DRV_STAT(rx_l4_port_errs),
+       NICVF_DRV_STAT(rx_tcp_flag_errs),
+       NICVF_DRV_STAT(rx_tcp_offset_errs),
+       NICVF_DRV_STAT(rx_l4_pclp),
+       NICVF_DRV_STAT(rx_truncated_pkts),
+
+       NICVF_DRV_STAT(tx_desc_fault),
+       NICVF_DRV_STAT(tx_hdr_cons_err),
+       NICVF_DRV_STAT(tx_subdesc_err),
+       NICVF_DRV_STAT(tx_max_size_exceeded),
+       NICVF_DRV_STAT(tx_imm_size_oflow),
+       NICVF_DRV_STAT(tx_data_seq_err),
+       NICVF_DRV_STAT(tx_mem_seq_err),
+       NICVF_DRV_STAT(tx_lock_viol),
+       NICVF_DRV_STAT(tx_data_fault),
+       NICVF_DRV_STAT(tx_tstmp_conflict),
+       NICVF_DRV_STAT(tx_tstmp_timeout),
+       NICVF_DRV_STAT(tx_mem_fault),
+       NICVF_DRV_STAT(tx_csum_overlap),
+       NICVF_DRV_STAT(tx_csum_overflow),
+
        NICVF_DRV_STAT(rcv_buffer_alloc_failures),
-       NICVF_DRV_STAT(tx_frames_ok),
        NICVF_DRV_STAT(tx_tso),
-       NICVF_DRV_STAT(tx_drops),
        NICVF_DRV_STAT(tx_timeout),
        NICVF_DRV_STAT(txq_stop),
        NICVF_DRV_STAT(txq_wake),
@@ -278,8 +287,8 @@ static void nicvf_get_ethtool_stats(struct net_device *netdev,
                                    struct ethtool_stats *stats, u64 *data)
 {
        struct nicvf *nic = netdev_priv(netdev);
-       int stat;
-       int sqs;
+       int stat, tmp_stats;
+       int sqs, cpu;
 
        nicvf_update_stats(nic);
 
@@ -289,9 +298,13 @@ static void nicvf_get_ethtool_stats(struct net_device *netdev,
        for (stat = 0; stat < nicvf_n_hw_stats; stat++)
                *(data++) = ((u64 *)&nic->hw_stats)
                                [nicvf_hw_stats[stat].index];
-       for (stat = 0; stat < nicvf_n_drv_stats; stat++)
-               *(data++) = ((u64 *)&nic->drv_stats)
-                               [nicvf_drv_stats[stat].index];
+       for (stat = 0; stat < nicvf_n_drv_stats; stat++) {
+               tmp_stats = 0;
+               for_each_possible_cpu(cpu)
+                       tmp_stats += ((u64 *)per_cpu_ptr(nic->drv_stats, cpu))
+                                    [nicvf_drv_stats[stat].index];
+               *(data++) = tmp_stats;
+       }
 
        nicvf_get_qset_stats(nic, stats, &data);
 
index 45a13f718863f33a6ccc7f14a37f2f2fc117be84..8a37012c9c89637560fc3ae7554718b0f96163e4 100644 (file)
@@ -69,25 +69,6 @@ static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx)
                return qidx;
 }
 
-static inline void nicvf_set_rx_frame_cnt(struct nicvf *nic,
-                                         struct sk_buff *skb)
-{
-       if (skb->len <= 64)
-               nic->drv_stats.rx_frames_64++;
-       else if (skb->len <= 127)
-               nic->drv_stats.rx_frames_127++;
-       else if (skb->len <= 255)
-               nic->drv_stats.rx_frames_255++;
-       else if (skb->len <= 511)
-               nic->drv_stats.rx_frames_511++;
-       else if (skb->len <= 1023)
-               nic->drv_stats.rx_frames_1023++;
-       else if (skb->len <= 1518)
-               nic->drv_stats.rx_frames_1518++;
-       else
-               nic->drv_stats.rx_frames_jumbo++;
-}
-
 /* The Cavium ThunderX network controller can *only* be found in SoCs
  * containing the ThunderX ARM64 CPU implementation.  All accesses to the device
  * registers on this platform are implicitly strongly ordered with respect
@@ -492,9 +473,6 @@ int nicvf_set_real_num_queues(struct net_device *netdev,
 static int nicvf_init_resources(struct nicvf *nic)
 {
        int err;
-       union nic_mbx mbx = {};
-
-       mbx.msg.msg = NIC_MBOX_MSG_CFG_DONE;
 
        /* Enable Qset */
        nicvf_qset_config(nic, true);
@@ -507,14 +485,10 @@ static int nicvf_init_resources(struct nicvf *nic)
                return err;
        }
 
-       /* Send VF config done msg to PF */
-       nicvf_write_to_mbx(nic, &mbx);
-
        return 0;
 }
 
 static void nicvf_snd_pkt_handler(struct net_device *netdev,
-                                 struct cmp_queue *cq,
                                  struct cqe_send_t *cqe_tx,
                                  int cqe_type, int budget,
                                  unsigned int *tx_pkts, unsigned int *tx_bytes)
@@ -536,7 +510,7 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev,
                   __func__, cqe_tx->sq_qs, cqe_tx->sq_idx,
                   cqe_tx->sqe_ptr, hdr->subdesc_cnt);
 
-       nicvf_check_cqe_tx_errs(nic, cq, cqe_tx);
+       nicvf_check_cqe_tx_errs(nic, cqe_tx);
        skb = (struct sk_buff *)sq->skbuff[cqe_tx->sqe_ptr];
        if (skb) {
                /* Check for dummy descriptor used for HW TSO offload on 88xx */
@@ -630,8 +604,6 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
                return;
        }
 
-       nicvf_set_rx_frame_cnt(nic, skb);
-
        nicvf_set_rxhash(netdev, cqe_rx, skb);
 
        skb_record_rx_queue(skb, rq_idx);
@@ -703,7 +675,7 @@ loop:
                        work_done++;
                break;
                case CQE_TYPE_SEND:
-                       nicvf_snd_pkt_handler(netdev, cq,
+                       nicvf_snd_pkt_handler(netdev,
                                              (void *)cq_desc, CQE_TYPE_SEND,
                                              budget, &tx_pkts, &tx_bytes);
                        tx_done++;
@@ -740,7 +712,7 @@ done:
                nic = nic->pnicvf;
                if (netif_tx_queue_stopped(txq) && netif_carrier_ok(netdev)) {
                        netif_tx_start_queue(txq);
-                       nic->drv_stats.txq_wake++;
+                       this_cpu_inc(nic->drv_stats->txq_wake);
                        if (netif_msg_tx_err(nic))
                                netdev_warn(netdev,
                                            "%s: Transmit queue wakeup SQ%d\n",
@@ -1084,7 +1056,7 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
 
        if (!netif_tx_queue_stopped(txq) && !nicvf_sq_append_skb(nic, skb)) {
                netif_tx_stop_queue(txq);
-               nic->drv_stats.txq_stop++;
+               this_cpu_inc(nic->drv_stats->txq_stop);
                if (netif_msg_tx_err(nic))
                        netdev_warn(netdev,
                                    "%s: Transmit ring full, stopping SQ%d\n",
@@ -1189,14 +1161,24 @@ int nicvf_stop(struct net_device *netdev)
        return 0;
 }
 
+static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu)
+{
+       union nic_mbx mbx = {};
+
+       mbx.frs.msg = NIC_MBOX_MSG_SET_MAX_FRS;
+       mbx.frs.max_frs = mtu;
+       mbx.frs.vf_id = nic->vf_id;
+
+       return nicvf_send_msg_to_pf(nic, &mbx);
+}
+
 int nicvf_open(struct net_device *netdev)
 {
-       int err, qidx;
+       int cpu, err, qidx;
        struct nicvf *nic = netdev_priv(netdev);
        struct queue_set *qs = nic->qs;
        struct nicvf_cq_poll *cq_poll = NULL;
-
-       nic->mtu = netdev->mtu;
+       union nic_mbx mbx = {};
 
        netif_carrier_off(netdev);
 
@@ -1248,9 +1230,17 @@ int nicvf_open(struct net_device *netdev)
        if (nic->sqs_mode)
                nicvf_get_primary_vf_struct(nic);
 
-       /* Configure receive side scaling */
-       if (!nic->sqs_mode)
+       /* Configure receive side scaling and MTU */
+       if (!nic->sqs_mode) {
                nicvf_rss_init(nic);
+               if (nicvf_update_hw_max_frs(nic, netdev->mtu))
+                       goto cleanup;
+
+               /* Clear percpu stats */
+               for_each_possible_cpu(cpu)
+                       memset(per_cpu_ptr(nic->drv_stats, cpu), 0,
+                              sizeof(struct nicvf_drv_stats));
+       }
 
        err = nicvf_register_interrupts(nic);
        if (err)
@@ -1276,8 +1266,9 @@ int nicvf_open(struct net_device *netdev)
        for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
                nicvf_enable_intr(nic, NICVF_INTR_RBDR, qidx);
 
-       nic->drv_stats.txq_stop = 0;
-       nic->drv_stats.txq_wake = 0;
+       /* Send VF config done msg to PF */
+       mbx.msg.msg = NIC_MBOX_MSG_CFG_DONE;
+       nicvf_write_to_mbx(nic, &mbx);
 
        return 0;
 cleanup:
@@ -1297,17 +1288,6 @@ napi_del:
        return err;
 }
 
-static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu)
-{
-       union nic_mbx mbx = {};
-
-       mbx.frs.msg = NIC_MBOX_MSG_SET_MAX_FRS;
-       mbx.frs.max_frs = mtu;
-       mbx.frs.vf_id = nic->vf_id;
-
-       return nicvf_send_msg_to_pf(nic, &mbx);
-}
-
 static int nicvf_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct nicvf *nic = netdev_priv(netdev);
@@ -1318,10 +1298,13 @@ static int nicvf_change_mtu(struct net_device *netdev, int new_mtu)
        if (new_mtu < NIC_HW_MIN_FRS)
                return -EINVAL;
 
+       netdev->mtu = new_mtu;
+
+       if (!netif_running(netdev))
+               return 0;
+
        if (nicvf_update_hw_max_frs(nic, new_mtu))
                return -EINVAL;
-       netdev->mtu = new_mtu;
-       nic->mtu = new_mtu;
 
        return 0;
 }
@@ -1379,9 +1362,10 @@ void nicvf_update_lmac_stats(struct nicvf *nic)
 
 void nicvf_update_stats(struct nicvf *nic)
 {
-       int qidx;
+       int qidx, cpu;
+       u64 tmp_stats = 0;
        struct nicvf_hw_stats *stats = &nic->hw_stats;
-       struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
+       struct nicvf_drv_stats *drv_stats;
        struct queue_set *qs = nic->qs;
 
 #define GET_RX_STATS(reg) \
@@ -1404,21 +1388,33 @@ void nicvf_update_stats(struct nicvf *nic)
        stats->rx_drop_l3_bcast = GET_RX_STATS(RX_DRP_L3BCAST);
        stats->rx_drop_l3_mcast = GET_RX_STATS(RX_DRP_L3MCAST);
 
-       stats->tx_bytes_ok = GET_TX_STATS(TX_OCTS);
-       stats->tx_ucast_frames_ok = GET_TX_STATS(TX_UCAST);
-       stats->tx_bcast_frames_ok = GET_TX_STATS(TX_BCAST);
-       stats->tx_mcast_frames_ok = GET_TX_STATS(TX_MCAST);
+       stats->tx_bytes = GET_TX_STATS(TX_OCTS);
+       stats->tx_ucast_frames = GET_TX_STATS(TX_UCAST);
+       stats->tx_bcast_frames = GET_TX_STATS(TX_BCAST);
+       stats->tx_mcast_frames = GET_TX_STATS(TX_MCAST);
        stats->tx_drops = GET_TX_STATS(TX_DROP);
 
-       drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok +
-                                 stats->tx_bcast_frames_ok +
-                                 stats->tx_mcast_frames_ok;
-       drv_stats->rx_frames_ok = stats->rx_ucast_frames +
-                                 stats->rx_bcast_frames +
-                                 stats->rx_mcast_frames;
-       drv_stats->rx_drops = stats->rx_drop_red +
-                             stats->rx_drop_overrun;
-       drv_stats->tx_drops = stats->tx_drops;
+       /* On T88 pass 2.0, the dummy SQE added for TSO notification
+        * via CQE has 'dont_send' set. Hence HW drops the pkt pointed
+        * pointed by dummy SQE and results in tx_drops counter being
+        * incremented. Subtracting it from tx_tso counter will give
+        * exact tx_drops counter.
+        */
+       if (nic->t88 && nic->hw_tso) {
+               for_each_possible_cpu(cpu) {
+                       drv_stats = per_cpu_ptr(nic->drv_stats, cpu);
+                       tmp_stats += drv_stats->tx_tso;
+               }
+               stats->tx_drops = tmp_stats - stats->tx_drops;
+       }
+       stats->tx_frames = stats->tx_ucast_frames +
+                          stats->tx_bcast_frames +
+                          stats->tx_mcast_frames;
+       stats->rx_frames = stats->rx_ucast_frames +
+                          stats->rx_bcast_frames +
+                          stats->rx_mcast_frames;
+       stats->rx_drops = stats->rx_drop_red +
+                         stats->rx_drop_overrun;
 
        /* Update RQ and SQ stats */
        for (qidx = 0; qidx < qs->rq_cnt; qidx++)
@@ -1432,18 +1428,17 @@ static struct rtnl_link_stats64 *nicvf_get_stats64(struct net_device *netdev,
 {
        struct nicvf *nic = netdev_priv(netdev);
        struct nicvf_hw_stats *hw_stats = &nic->hw_stats;
-       struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
 
        nicvf_update_stats(nic);
 
        stats->rx_bytes = hw_stats->rx_bytes;
-       stats->rx_packets = drv_stats->rx_frames_ok;
-       stats->rx_dropped = drv_stats->rx_drops;
+       stats->rx_packets = hw_stats->rx_frames;
+       stats->rx_dropped = hw_stats->rx_drops;
        stats->multicast = hw_stats->rx_mcast_frames;
 
-       stats->tx_bytes = hw_stats->tx_bytes_ok;
-       stats->tx_packets = drv_stats->tx_frames_ok;
-       stats->tx_dropped = drv_stats->tx_drops;
+       stats->tx_bytes = hw_stats->tx_bytes;
+       stats->tx_packets = hw_stats->tx_frames;
+       stats->tx_dropped = hw_stats->tx_drops;
 
        return stats;
 }
@@ -1456,7 +1451,7 @@ static void nicvf_tx_timeout(struct net_device *dev)
                netdev_warn(dev, "%s: Transmit timed out, resetting\n",
                            dev->name);
 
-       nic->drv_stats.tx_timeout++;
+       this_cpu_inc(nic->drv_stats->tx_timeout);
        schedule_work(&nic->reset_task);
 }
 
@@ -1590,6 +1585,12 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_free_netdev;
        }
 
+       nic->drv_stats = netdev_alloc_pcpu_stats(struct nicvf_drv_stats);
+       if (!nic->drv_stats) {
+               err = -ENOMEM;
+               goto err_free_netdev;
+       }
+
        err = nicvf_set_qset_resources(nic);
        if (err)
                goto err_free_netdev;
@@ -1648,6 +1649,8 @@ err_unregister_interrupts:
        nicvf_unregister_interrupts(nic);
 err_free_netdev:
        pci_set_drvdata(pdev, NULL);
+       if (nic->drv_stats)
+               free_percpu(nic->drv_stats);
        free_netdev(netdev);
 err_release_regions:
        pci_release_regions(pdev);
@@ -1675,6 +1678,8 @@ static void nicvf_remove(struct pci_dev *pdev)
                unregister_netdev(pnetdev);
        nicvf_unregister_interrupts(nic);
        pci_set_drvdata(pdev, NULL);
+       if (nic->drv_stats)
+               free_percpu(nic->drv_stats);
        free_netdev(netdev);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
index a4fc501558817639fbc0da5cb9bb388f0f49a51f..747ef08829763db89b8fb1802eab9b47a0eef6b0 100644 (file)
@@ -104,7 +104,8 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, gfp_t gfp,
                nic->rb_page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
                                           order);
                if (!nic->rb_page) {
-                       nic->drv_stats.rcv_buffer_alloc_failures++;
+                       this_cpu_inc(nic->pnicvf->drv_stats->
+                                    rcv_buffer_alloc_failures);
                        return -ENOMEM;
                }
                nic->rb_page_offset = 0;
@@ -270,7 +271,8 @@ refill:
                              rbdr_idx, new_rb);
 next_rbdr:
        /* Re-enable RBDR interrupts only if buffer allocation is success */
-       if (!nic->rb_alloc_fail && rbdr->enable)
+       if (!nic->rb_alloc_fail && rbdr->enable &&
+           netif_running(nic->pnicvf->netdev))
                nicvf_enable_intr(nic, NICVF_INTR_RBDR, rbdr_idx);
 
        if (rbdr_idx)
@@ -361,6 +363,8 @@ static int nicvf_init_snd_queue(struct nicvf *nic,
 
 static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
 {
+       struct sk_buff *skb;
+
        if (!sq)
                return;
        if (!sq->dmem.base)
@@ -371,6 +375,15 @@ static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
                                  sq->dmem.q_len * TSO_HEADER_SIZE,
                                  sq->tso_hdrs, sq->tso_hdrs_phys);
 
+       /* Free pending skbs in the queue */
+       smp_rmb();
+       while (sq->head != sq->tail) {
+               skb = (struct sk_buff *)sq->skbuff[sq->head];
+               if (skb)
+                       dev_kfree_skb_any(skb);
+               sq->head++;
+               sq->head &= (sq->dmem.q_len - 1);
+       }
        kfree(sq->skbuff);
        nicvf_free_q_desc_mem(nic, &sq->dmem);
 }
@@ -483,9 +496,12 @@ static void nicvf_reset_rcv_queue_stats(struct nicvf *nic)
 {
        union nic_mbx mbx = {};
 
-       /* Reset all RXQ's stats */
+       /* Reset all RQ/SQ and VF stats */
        mbx.reset_stat.msg = NIC_MBOX_MSG_RESET_STAT_COUNTER;
+       mbx.reset_stat.rx_stat_mask = 0x3FFF;
+       mbx.reset_stat.tx_stat_mask = 0x1F;
        mbx.reset_stat.rq_stat_mask = 0xFFFF;
+       mbx.reset_stat.sq_stat_mask = 0xFFFF;
        nicvf_send_msg_to_pf(nic, &mbx);
 }
 
@@ -538,9 +554,12 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
        mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8);
        nicvf_send_msg_to_pf(nic, &mbx);
 
-       nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, 0x00);
-       if (!nic->sqs_mode)
+       if (!nic->sqs_mode && (qidx == 0)) {
+               /* Enable checking L3/L4 length and TCP/UDP checksums */
+               nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0,
+                                     (BIT(24) | BIT(23) | BIT(21)));
                nicvf_config_vlan_stripping(nic, nic->netdev->features);
+       }
 
        /* Enable Receive queue */
        memset(&rq_cfg, 0, sizeof(struct rq_cfg));
@@ -1029,7 +1048,7 @@ nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry,
                hdr->tso_max_paysize = skb_shinfo(skb)->gso_size;
                /* For non-tunneled pkts, point this to L2 ethertype */
                hdr->inner_l3_offset = skb_network_offset(skb) - 2;
-               nic->drv_stats.tx_tso++;
+               this_cpu_inc(nic->pnicvf->drv_stats->tx_tso);
        }
 }
 
@@ -1161,7 +1180,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
 
        nicvf_sq_doorbell(nic, skb, sq_num, desc_cnt);
 
-       nic->drv_stats.tx_tso++;
+       this_cpu_inc(nic->pnicvf->drv_stats->tx_tso);
        return 1;
 }
 
@@ -1422,8 +1441,6 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)
 /* Check for errors in the receive cmp.queue entry */
 int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
 {
-       struct nicvf_hw_stats *stats = &nic->hw_stats;
-
        if (!cqe_rx->err_level && !cqe_rx->err_opcode)
                return 0;
 
@@ -1435,76 +1452,76 @@ int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
 
        switch (cqe_rx->err_opcode) {
        case CQ_RX_ERROP_RE_PARTIAL:
-               stats->rx_bgx_truncated_pkts++;
+               this_cpu_inc(nic->drv_stats->rx_bgx_truncated_pkts);
                break;
        case CQ_RX_ERROP_RE_JABBER:
-               stats->rx_jabber_errs++;
+               this_cpu_inc(nic->drv_stats->rx_jabber_errs);
                break;
        case CQ_RX_ERROP_RE_FCS:
-               stats->rx_fcs_errs++;
+               this_cpu_inc(nic->drv_stats->rx_fcs_errs);
                break;
        case CQ_RX_ERROP_RE_RX_CTL:
-               stats->rx_bgx_errs++;
+               this_cpu_inc(nic->drv_stats->rx_bgx_errs);
                break;
        case CQ_RX_ERROP_PREL2_ERR:
-               stats->rx_prel2_errs++;
+               this_cpu_inc(nic->drv_stats->rx_prel2_errs);
                break;
        case CQ_RX_ERROP_L2_MAL:
-               stats->rx_l2_hdr_malformed++;
+               this_cpu_inc(nic->drv_stats->rx_l2_hdr_malformed);
                break;
        case CQ_RX_ERROP_L2_OVERSIZE:
-               stats->rx_oversize++;
+               this_cpu_inc(nic->drv_stats->rx_oversize);
                break;
        case CQ_RX_ERROP_L2_UNDERSIZE:
-               stats->rx_undersize++;
+               this_cpu_inc(nic->drv_stats->rx_undersize);
                break;
        case CQ_RX_ERROP_L2_LENMISM:
-               stats->rx_l2_len_mismatch++;
+               this_cpu_inc(nic->drv_stats->rx_l2_len_mismatch);
                break;
        case CQ_RX_ERROP_L2_PCLP:
-               stats->rx_l2_pclp++;
+               this_cpu_inc(nic->drv_stats->rx_l2_pclp);
                break;
        case CQ_RX_ERROP_IP_NOT:
-               stats->rx_ip_ver_errs++;
+               this_cpu_inc(nic->drv_stats->rx_ip_ver_errs);
                break;
        case CQ_RX_ERROP_IP_CSUM_ERR:
-               stats->rx_ip_csum_errs++;
+               this_cpu_inc(nic->drv_stats->rx_ip_csum_errs);
                break;
        case CQ_RX_ERROP_IP_MAL:
-               stats->rx_ip_hdr_malformed++;
+               this_cpu_inc(nic->drv_stats->rx_ip_hdr_malformed);
                break;
        case CQ_RX_ERROP_IP_MALD:
-               stats->rx_ip_payload_malformed++;
+               this_cpu_inc(nic->drv_stats->rx_ip_payload_malformed);
                break;
        case CQ_RX_ERROP_IP_HOP:
-               stats->rx_ip_ttl_errs++;
+               this_cpu_inc(nic->drv_stats->rx_ip_ttl_errs);
                break;
        case CQ_RX_ERROP_L3_PCLP:
-               stats->rx_l3_pclp++;
+               this_cpu_inc(nic->drv_stats->rx_l3_pclp);
                break;
        case CQ_RX_ERROP_L4_MAL:
-               stats->rx_l4_malformed++;
+               this_cpu_inc(nic->drv_stats->rx_l4_malformed);
                break;
        case CQ_RX_ERROP_L4_CHK:
-               stats->rx_l4_csum_errs++;
+               this_cpu_inc(nic->drv_stats->rx_l4_csum_errs);
                break;
        case CQ_RX_ERROP_UDP_LEN:
-               stats->rx_udp_len_errs++;
+               this_cpu_inc(nic->drv_stats->rx_udp_len_errs);
                break;
        case CQ_RX_ERROP_L4_PORT:
-               stats->rx_l4_port_errs++;
+               this_cpu_inc(nic->drv_stats->rx_l4_port_errs);
                break;
        case CQ_RX_ERROP_TCP_FLAG:
-               stats->rx_tcp_flag_errs++;
+               this_cpu_inc(nic->drv_stats->rx_tcp_flag_errs);
                break;
        case CQ_RX_ERROP_TCP_OFFSET:
-               stats->rx_tcp_offset_errs++;
+               this_cpu_inc(nic->drv_stats->rx_tcp_offset_errs);
                break;
        case CQ_RX_ERROP_L4_PCLP:
-               stats->rx_l4_pclp++;
+               this_cpu_inc(nic->drv_stats->rx_l4_pclp);
                break;
        case CQ_RX_ERROP_RBDR_TRUNC:
-               stats->rx_truncated_pkts++;
+               this_cpu_inc(nic->drv_stats->rx_truncated_pkts);
                break;
        }
 
@@ -1512,53 +1529,52 @@ int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
 }
 
 /* Check for errors in the send cmp.queue entry */
-int nicvf_check_cqe_tx_errs(struct nicvf *nic,
-                           struct cmp_queue *cq, struct cqe_send_t *cqe_tx)
+int nicvf_check_cqe_tx_errs(struct nicvf *nic, struct cqe_send_t *cqe_tx)
 {
-       struct cmp_queue_stats *stats = &cq->stats;
-
        switch (cqe_tx->send_status) {
        case CQ_TX_ERROP_GOOD:
-               stats->tx.good++;
                return 0;
        case CQ_TX_ERROP_DESC_FAULT:
-               stats->tx.desc_fault++;
+               this_cpu_inc(nic->drv_stats->tx_desc_fault);
                break;
        case CQ_TX_ERROP_HDR_CONS_ERR:
-               stats->tx.hdr_cons_err++;
+               this_cpu_inc(nic->drv_stats->tx_hdr_cons_err);
                break;
        case CQ_TX_ERROP_SUBDC_ERR:
-               stats->tx.subdesc_err++;
+               this_cpu_inc(nic->drv_stats->tx_subdesc_err);
+               break;
+       case CQ_TX_ERROP_MAX_SIZE_VIOL:
+               this_cpu_inc(nic->drv_stats->tx_max_size_exceeded);
                break;
        case CQ_TX_ERROP_IMM_SIZE_OFLOW:
-               stats->tx.imm_size_oflow++;
+               this_cpu_inc(nic->drv_stats->tx_imm_size_oflow);
                break;
        case CQ_TX_ERROP_DATA_SEQUENCE_ERR:
-               stats->tx.data_seq_err++;
+               this_cpu_inc(nic->drv_stats->tx_data_seq_err);
                break;
        case CQ_TX_ERROP_MEM_SEQUENCE_ERR:
-               stats->tx.mem_seq_err++;
+               this_cpu_inc(nic->drv_stats->tx_mem_seq_err);
                break;
        case CQ_TX_ERROP_LOCK_VIOL:
-               stats->tx.lock_viol++;
+               this_cpu_inc(nic->drv_stats->tx_lock_viol);
                break;
        case CQ_TX_ERROP_DATA_FAULT:
-               stats->tx.data_fault++;
+               this_cpu_inc(nic->drv_stats->tx_data_fault);
                break;
        case CQ_TX_ERROP_TSTMP_CONFLICT:
-               stats->tx.tstmp_conflict++;
+               this_cpu_inc(nic->drv_stats->tx_tstmp_conflict);
                break;
        case CQ_TX_ERROP_TSTMP_TIMEOUT:
-               stats->tx.tstmp_timeout++;
+               this_cpu_inc(nic->drv_stats->tx_tstmp_timeout);
                break;
        case CQ_TX_ERROP_MEM_FAULT:
-               stats->tx.mem_fault++;
+               this_cpu_inc(nic->drv_stats->tx_mem_fault);
                break;
        case CQ_TX_ERROP_CK_OVERLAP:
-               stats->tx.csum_overlap++;
+               this_cpu_inc(nic->drv_stats->tx_csum_overlap);
                break;
        case CQ_TX_ERROP_CK_OFLOW:
-               stats->tx.csum_overflow++;
+               this_cpu_inc(nic->drv_stats->tx_csum_overflow);
                break;
        }
 
index 869f3386028b1e765c4860cf86560f1f6b564b42..2e3c940c10933049b81c590d1f0ff72bb79a13f0 100644 (file)
@@ -158,6 +158,7 @@ enum CQ_TX_ERROP_E {
        CQ_TX_ERROP_DESC_FAULT = 0x10,
        CQ_TX_ERROP_HDR_CONS_ERR = 0x11,
        CQ_TX_ERROP_SUBDC_ERR = 0x12,
+       CQ_TX_ERROP_MAX_SIZE_VIOL = 0x13,
        CQ_TX_ERROP_IMM_SIZE_OFLOW = 0x80,
        CQ_TX_ERROP_DATA_SEQUENCE_ERR = 0x81,
        CQ_TX_ERROP_MEM_SEQUENCE_ERR = 0x82,
@@ -171,25 +172,6 @@ enum CQ_TX_ERROP_E {
        CQ_TX_ERROP_ENUM_LAST = 0x8a,
 };
 
-struct cmp_queue_stats {
-       struct tx_stats {
-               u64 good;
-               u64 desc_fault;
-               u64 hdr_cons_err;
-               u64 subdesc_err;
-               u64 imm_size_oflow;
-               u64 data_seq_err;
-               u64 mem_seq_err;
-               u64 lock_viol;
-               u64 data_fault;
-               u64 tstmp_conflict;
-               u64 tstmp_timeout;
-               u64 mem_fault;
-               u64 csum_overlap;
-               u64 csum_overflow;
-       } tx;
-} ____cacheline_aligned_in_smp;
-
 enum RQ_SQ_STATS {
        RQ_SQ_STATS_OCTS,
        RQ_SQ_STATS_PKTS,
@@ -241,7 +223,6 @@ struct cmp_queue {
        spinlock_t      lock;  /* lock to serialize processing CQEs */
        void            *desc;
        struct q_desc_mem   dmem;
-       struct cmp_queue_stats  stats;
        int             irq;
 } ____cacheline_aligned_in_smp;
 
@@ -336,6 +317,5 @@ u64  nicvf_queue_reg_read(struct nicvf *nic,
 void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);
 void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx);
 int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx);
-int nicvf_check_cqe_tx_errs(struct nicvf *nic,
-                           struct cmp_queue *cq, struct cqe_send_t *cqe_tx);
+int nicvf_check_cqe_tx_errs(struct nicvf *nic, struct cqe_send_t *cqe_tx);
 #endif /* NICVF_QUEUES_H */
index 8bbaedbb7b946353470f4bb57138f542025b068b..050e21fbb1471d5fa86f735386d90491660cce43 100644 (file)
@@ -1242,8 +1242,8 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_read_config_word(pdev, PCI_DEVICE_ID, &sdevid);
        if (sdevid != PCI_DEVICE_ID_THUNDER_RGX) {
-               bgx->bgx_id =
-                   (pci_resource_start(pdev, PCI_CFG_REG_BAR_NUM) >> 24) & 1;
+               bgx->bgx_id = (pci_resource_start(pdev,
+                       PCI_CFG_REG_BAR_NUM) >> 24) & BGX_ID_MASK;
                bgx->bgx_id += nic_get_node_id(pdev) * MAX_BGX_PER_NODE;
                bgx->max_lmac = MAX_LMAC_PER_BGX;
                bgx_vnic[bgx->bgx_id] = bgx;
index d59c71e4a0008bb576c1c3a6e192eb225381c82a..01cc7c8591313fca033a7e791bc57ccd9adb776b 100644 (file)
@@ -28,6 +28,8 @@
 #define    MAX_DMAC_PER_LMAC                   8
 #define    MAX_FRAME_SIZE                      9216
 
+#define           BGX_ID_MASK                          0x3
+
 #define    MAX_DMAC_PER_LMAC_TNS_BYPASS_MODE   2
 
 /* Registers */
index f320497368f401deb36a3c1b93d0e288208a7fec..19dc9e25aa72d20e0050f5b3f2080e9704647f71 100644 (file)
@@ -4057,7 +4057,7 @@ static void cfg_queues(struct adapter *adap)
                 * capped by the number of available cores.
                 */
                if (n10g) {
-                       i = num_online_cpus();
+                       i = min_t(int, MAX_OFLD_QSETS, num_online_cpus());
                        s->ofldqsets = roundup(i, adap->params.nports);
                } else {
                        s->ofldqsets = adap->params.nports;
@@ -4931,6 +4931,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
         */
        for_each_port(adapter, i) {
                pi = adap2pinfo(adapter, i);
+               adapter->port[i]->dev_port = pi->lport;
                netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets);
                netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets);
 
index 0945fa49a5dd83251af4083535b27f081ae277b0..2471ff465d5c6eb83395453f9a367b36fb8ad3a1 100644 (file)
@@ -135,15 +135,17 @@ static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp,
 }
 
 static int alloc_uld_rxqs(struct adapter *adap,
-                         struct sge_uld_rxq_info *rxq_info,
-                         unsigned int nq, unsigned int offset, bool lro)
+                         struct sge_uld_rxq_info *rxq_info, bool lro)
 {
        struct sge *s = &adap->sge;
-       struct sge_ofld_rxq *q = rxq_info->uldrxq + offset;
-       unsigned short *ids = rxq_info->rspq_id + offset;
-       unsigned int per_chan = nq / adap->params.nports;
+       unsigned int nq = rxq_info->nrxq + rxq_info->nciq;
+       struct sge_ofld_rxq *q = rxq_info->uldrxq;
+       unsigned short *ids = rxq_info->rspq_id;
        unsigned int bmap_idx = 0;
-       int i, err, msi_idx;
+       unsigned int per_chan;
+       int i, err, msi_idx, que_idx = 0;
+
+       per_chan = rxq_info->nrxq / adap->params.nports;
 
        if (adap->flags & USING_MSIX)
                msi_idx = 1;
@@ -151,12 +153,18 @@ static int alloc_uld_rxqs(struct adapter *adap,
                msi_idx = -((int)s->intrq.abs_id + 1);
 
        for (i = 0; i < nq; i++, q++) {
+               if (i == rxq_info->nrxq) {
+                       /* start allocation of concentrator queues */
+                       per_chan = rxq_info->nciq / adap->params.nports;
+                       que_idx = 0;
+               }
+
                if (msi_idx >= 0) {
                        bmap_idx = get_msix_idx_from_bmap(adap);
                        msi_idx = adap->msix_info_ulds[bmap_idx].idx;
                }
                err = t4_sge_alloc_rxq(adap, &q->rspq, false,
-                                      adap->port[i / per_chan],
+                                      adap->port[que_idx++ / per_chan],
                                       msi_idx,
                                       q->fl.size ? &q->fl : NULL,
                                       uldrx_handler,
@@ -165,29 +173,19 @@ static int alloc_uld_rxqs(struct adapter *adap,
                if (err)
                        goto freeout;
                if (msi_idx >= 0)
-                       rxq_info->msix_tbl[i + offset] = bmap_idx;
+                       rxq_info->msix_tbl[i] = bmap_idx;
                memset(&q->stats, 0, sizeof(q->stats));
                if (ids)
                        ids[i] = q->rspq.abs_id;
        }
        return 0;
 freeout:
-       q = rxq_info->uldrxq + offset;
+       q = rxq_info->uldrxq;
        for ( ; i; i--, q++) {
                if (q->rspq.desc)
                        free_rspq_fl(adap, &q->rspq,
                                     q->fl.size ? &q->fl : NULL);
        }
-
-       /* We need to free rxq also in case of ciq allocation failure */
-       if (offset) {
-               q = rxq_info->uldrxq + offset;
-               for ( ; i; i--, q++) {
-                       if (q->rspq.desc)
-                               free_rspq_fl(adap, &q->rspq,
-                                            q->fl.size ? &q->fl : NULL);
-               }
-       }
        return err;
 }
 
@@ -205,9 +203,7 @@ setup_sge_queues_uld(struct adapter *adap, unsigned int uld_type, bool lro)
                        return -ENOMEM;
        }
 
-       ret = !(!alloc_uld_rxqs(adap, rxq_info, rxq_info->nrxq, 0, lro) &&
-                !alloc_uld_rxqs(adap, rxq_info, rxq_info->nciq,
-                                rxq_info->nrxq, lro));
+       ret = !(!alloc_uld_rxqs(adap, rxq_info, lro));
 
        /* Tell uP to route control queue completions to rdma rspq */
        if (adap->flags & FULL_INIT_DONE &&
index 539de764bbd30af3d2e148e9220228e710d6d3f5..cbd68a8fe2e48b54bd5a9296eac7e8cca32063e4 100644 (file)
@@ -210,8 +210,10 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p)
 
        /* Unbind queue from any existing class */
        err = t4_sched_queue_unbind(pi, p);
-       if (err)
+       if (err) {
+               t4_free_mem(qe);
                goto out;
+       }
 
        /* Bind queue to specified class */
        memset(qe, 0, sizeof(*qe));
index 1e74fd6085df43b954f2343cd47ba1f8b592deaf..e19a0ca8e5ddb315ec5900c327bce9cab69ee96c 100644 (file)
@@ -2951,7 +2951,6 @@ void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
                   rq->cntxt_id, fl_id, 0xffff);
        dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len,
                          rq->desc, rq->phys_addr);
-       napi_hash_del(&rq->napi);
        netif_napi_del(&rq->napi);
        rq->netdev = NULL;
        rq->cntxt_id = rq->abs_id = 0;
index 20dec85da63db1fd2d871bf35f10368c5db39ab9..e8139514d32ca5ee2df37167d480681e381e37ae 100644 (file)
@@ -7851,7 +7851,6 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
                        return ret;
 
                memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
-               adap->port[i]->dev_port = j;
                j++;
        }
        return 0;
index 50812a1d67bdf8aab1ca8cb5fe560c7c5e2cb778..ecf3ccc257bcc4fc81e8cf35647982f8c4186763 100644 (file)
@@ -168,6 +168,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN
        CH_PCI_ID_TABLE_FENTRY(0x509a), /* Custom T520-CR */
        CH_PCI_ID_TABLE_FENTRY(0x509b), /* Custom T540-CR LOM */
        CH_PCI_ID_TABLE_FENTRY(0x509c), /* Custom T520-CR*/
+       CH_PCI_ID_TABLE_FENTRY(0x509d), /* Custom T540-CR*/
 
        /* T6 adapters:
         */
@@ -178,9 +179,9 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN
        CH_PCI_ID_TABLE_FENTRY(0x6005),
        CH_PCI_ID_TABLE_FENTRY(0x6006),
        CH_PCI_ID_TABLE_FENTRY(0x6007),
+       CH_PCI_ID_TABLE_FENTRY(0x6008),
        CH_PCI_ID_TABLE_FENTRY(0x6009),
        CH_PCI_ID_TABLE_FENTRY(0x600d),
-       CH_PCI_ID_TABLE_FENTRY(0x6010),
        CH_PCI_ID_TABLE_FENTRY(0x6011),
        CH_PCI_ID_TABLE_FENTRY(0x6014),
        CH_PCI_ID_TABLE_FENTRY(0x6015),
index 100b2cc064a34cafe8faac0e16e9ce44aa1a4f95..a37481c04a87b6a16541e1d2786a2357a946d82d 100644 (file)
@@ -2969,6 +2969,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
 
                netdev->netdev_ops = &cxgb4vf_netdev_ops;
                netdev->ethtool_ops = &cxgb4vf_ethtool_ops;
+               netdev->dev_port = pi->port_id;
 
                /*
                 * Initialize the hardware/software state for the port.
index de9f7c97d916d3d8d760282e726cf49f4181a56b..9a161e98152978fcfbafa51a959e214426a90bd9 100644 (file)
@@ -468,6 +468,9 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep)
        struct device *dev = ep->dev->dev.parent;
        int i;
 
+       if (!ep->descs)
+               return;
+
        for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
                dma_addr_t d;
 
@@ -490,6 +493,7 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep)
 
        dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs,
                                                        ep->descs_dma_addr);
+       ep->descs = NULL;
 }
 
 static int ep93xx_alloc_buffers(struct ep93xx_priv *ep)
index e572a527b18dd593c54e52e33386481fc9fbe95b..36bc2c71fba981bdd05d73c7e5b4537b07e19cab 100644 (file)
@@ -169,19 +169,28 @@ int vnic_rq_disable(struct vnic_rq *rq)
 {
        unsigned int wait;
        struct vnic_dev *vdev = rq->vdev;
+       int i;
 
-       iowrite32(0, &rq->ctrl->enable);
+       /* Due to a race condition with clearing RQ "mini-cache" in hw, we need
+        * to disable the RQ twice to guarantee that stale descriptors are not
+        * used when this RQ is re-enabled.
+        */
+       for (i = 0; i < 2; i++) {
+               iowrite32(0, &rq->ctrl->enable);
 
-       /* Wait for HW to ACK disable request */
-       for (wait = 0; wait < 1000; wait++) {
-               if (!(ioread32(&rq->ctrl->running)))
-                       return 0;
-               udelay(10);
-       }
+               /* Wait for HW to ACK disable request */
+               for (wait = 20000; wait > 0; wait--)
+                       if (!ioread32(&rq->ctrl->running))
+                               break;
+               if (!wait) {
+                       vdev_neterr(vdev, "Failed to disable RQ[%d]\n",
+                                   rq->index);
 
-       vdev_neterr(vdev, "Failed to disable RQ[%d]\n", rq->index);
+                       return -ETIMEDOUT;
+               }
+       }
 
-       return -ETIMEDOUT;
+       return 0;
 }
 
 void vnic_rq_clean(struct vnic_rq *rq,
@@ -212,6 +221,11 @@ void vnic_rq_clean(struct vnic_rq *rq,
                        [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES(count)];
        iowrite32(fetch_index, &rq->ctrl->posted_index);
 
+       /* Anytime we write fetch_index, we need to re-write 0 to rq->enable
+        * to re-sync internal VIC state.
+        */
+       iowrite32(0, &rq->ctrl->enable);
+
        vnic_dev_clear_desc_ring(&rq->ring);
 }
 
index 1fb5d72392547dcbc116fabe0fa9699de5e9c304..0e74529a42095b311c97dc367c2ba3b20bdfc27c 100644 (file)
@@ -90,7 +90,8 @@ static struct be_cmd_priv_map cmd_priv_map[] = {
        {
                OPCODE_COMMON_SET_HSW_CONFIG,
                CMD_SUBSYSTEM_COMMON,
-               BE_PRIV_DEVCFG | BE_PRIV_VHADM
+               BE_PRIV_DEVCFG | BE_PRIV_VHADM |
+               BE_PRIV_DEVSEC
        },
        {
                OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES,
index cece8a08edca1de45c4c56f89704ddd8523d7a3f..93aa2939142a226928c2be5926f772a234cd1294 100644 (file)
@@ -2813,7 +2813,6 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)
                if (eqo->q.created) {
                        be_eq_clean(eqo);
                        be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
-                       napi_hash_del(&eqo->napi);
                        netif_napi_del(&eqo->napi);
                        free_cpumask_var(eqo->affinity_mask);
                }
index f928e6f79c8954ed24408ddf0ad21faed4dd4870..223f35cc034cf4f9846856d1cbb4c551a0014747 100644 (file)
@@ -669,6 +669,7 @@ static const struct of_device_id nps_enet_dt_ids[] = {
        { .compatible = "ezchip,nps-mgt-enet" },
        { /* Sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, nps_enet_dt_ids);
 
 static struct platform_driver nps_enet_driver = {
        .probe = nps_enet_probe,
index c865135f3cb91bcb120e0b91aaba000577689e66..5ea740b4cf14c9db2350b6f46feb70c365e82a21 100644 (file)
@@ -574,6 +574,8 @@ struct fec_enet_private {
        unsigned int reload_period;
        int pps_enable;
        unsigned int next_counter;
+
+       u64 ethtool_stats[0];
 };
 
 void fec_ptp_init(struct platform_device *pdev);
index 48a033e64423dcde7e41c589e0b25466ea266002..12aef1b15356b00ad0139d6cb26f264ace84925d 100644 (file)
@@ -1430,14 +1430,14 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
                skb_put(skb, pkt_len - 4);
                data = skb->data;
 
+               if (!is_copybreak && need_swap)
+                       swap_buffer(data, pkt_len);
+
 #if !defined(CONFIG_M5272)
                if (fep->quirks & FEC_QUIRK_HAS_RACC)
                        data = skb_pull_inline(skb, 2);
 #endif
 
-               if (!is_copybreak && need_swap)
-                       swap_buffer(data, pkt_len);
-
                /* Extract the enhanced buffer descriptor */
                ebdp = NULL;
                if (fep->bufdesc_ex)
@@ -2313,14 +2313,26 @@ static const struct fec_stat {
        { "IEEE_rx_octets_ok", IEEE_R_OCTETS_OK },
 };
 
-static void fec_enet_get_ethtool_stats(struct net_device *dev,
-       struct ethtool_stats *stats, u64 *data)
+#define FEC_STATS_SIZE         (ARRAY_SIZE(fec_stats) * sizeof(u64))
+
+static void fec_enet_update_ethtool_stats(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
-               data[i] = readl(fep->hwp + fec_stats[i].offset);
+               fep->ethtool_stats[i] = readl(fep->hwp + fec_stats[i].offset);
+}
+
+static void fec_enet_get_ethtool_stats(struct net_device *dev,
+                                      struct ethtool_stats *stats, u64 *data)
+{
+       struct fec_enet_private *fep = netdev_priv(dev);
+
+       if (netif_running(dev))
+               fec_enet_update_ethtool_stats(dev);
+
+       memcpy(data, fep->ethtool_stats, FEC_STATS_SIZE);
 }
 
 static void fec_enet_get_strings(struct net_device *netdev,
@@ -2345,6 +2357,12 @@ static int fec_enet_get_sset_count(struct net_device *dev, int sset)
                return -EOPNOTSUPP;
        }
 }
+
+#else  /* !defined(CONFIG_M5272) */
+#define FEC_STATS_SIZE 0
+static inline void fec_enet_update_ethtool_stats(struct net_device *dev)
+{
+}
 #endif /* !defined(CONFIG_M5272) */
 
 static int fec_enet_nway_reset(struct net_device *dev)
@@ -2874,6 +2892,8 @@ fec_enet_close(struct net_device *ndev)
        if (fep->quirks & FEC_QUIRK_ERR006687)
                imx6q_cpuidle_fec_irqs_unused();
 
+       fec_enet_update_ethtool_stats(ndev);
+
        fec_enet_clk_enable(ndev, false);
        pinctrl_pm_select_sleep_state(&fep->pdev->dev);
        pm_runtime_mark_last_busy(&fep->pdev->dev);
@@ -3180,6 +3200,8 @@ static int fec_enet_init(struct net_device *ndev)
 
        fec_restart(ndev);
 
+       fec_enet_update_ethtool_stats(ndev);
+
        return 0;
 }
 
@@ -3278,8 +3300,8 @@ fec_probe(struct platform_device *pdev)
        fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
 
        /* Init network device */
-       ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
-                                 num_tx_qs, num_rx_qs);
+       ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private) +
+                                 FEC_STATS_SIZE, num_tx_qs, num_rx_qs);
        if (!ndev)
                return -ENOMEM;
 
@@ -3475,6 +3497,8 @@ failed_regulator:
 failed_clk_ipg:
        fec_enet_clk_enable(ndev, false);
 failed_clk:
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
 failed_phy:
        of_node_put(phy_node);
 failed_ioremap:
@@ -3488,6 +3512,7 @@ fec_drv_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
+       struct device_node *np = pdev->dev.of_node;
 
        cancel_work_sync(&fep->tx_timeout_work);
        fec_ptp_stop(pdev);
@@ -3495,6 +3520,8 @@ fec_drv_remove(struct platform_device *pdev)
        fec_enet_mii_remove(fep);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
        of_node_put(fep->phy_node);
        free_netdev(ndev);
 
index 53ef51e3bd9ef2cb3c5f8100f807399ab36a31d1..71a5ded9d1de0fda2f08c32985cc7661a3af3966 100644 (file)
@@ -1107,6 +1107,9 @@ int memac_free(struct fman_mac *memac)
 {
        free_init_resources(memac);
 
+       if (memac->pcsphy)
+               put_device(&memac->pcsphy->mdio.dev);
+
        kfree(memac->memac_drv_param);
        kfree(memac);
 
index efabb04a1ae8cc445fab85eab8c8aede0dcd0a58..4b0f3a50b2939aa31fc6274235e263f1277461fb 100644 (file)
@@ -722,9 +722,6 @@ int tgec_free(struct fman_mac *tgec)
 {
        free_init_resources(tgec);
 
-       if (tgec->cfg)
-               tgec->cfg = NULL;
-
        kfree(tgec->cfg);
        kfree(tgec);
 
index 8fe6b3e253fa436f0cc87bf8702b827f3b6d9a72..736db9d9b0ad0f2d3be32a033b1a2df176826af6 100644 (file)
@@ -892,6 +892,8 @@ static int mac_probe(struct platform_device *_of_dev)
                priv->fixed_link->duplex = phy->duplex;
                priv->fixed_link->pause = phy->pause;
                priv->fixed_link->asym_pause = phy->asym_pause;
+
+               put_device(&phy->mdio.dev);
        }
 
        err = mac_dev->init(mac_dev);
index dc120c148d9766fcf511f100396cb51f4b61a73b..4b86260584a056ead8a46f418d4a8cf52216aaad 100644 (file)
@@ -980,7 +980,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
                err = clk_prepare_enable(clk);
                if (err) {
                        ret = err;
-                       goto out_free_fpi;
+                       goto out_deregister_fixed_link;
                }
                fpi->clk_per = clk;
        }
@@ -1061,6 +1061,9 @@ out_put:
        of_node_put(fpi->phy_node);
        if (fpi->clk_per)
                clk_disable_unprepare(fpi->clk_per);
+out_deregister_fixed_link:
+       if (of_phy_is_fixed_link(ofdev->dev.of_node))
+               of_phy_deregister_fixed_link(ofdev->dev.of_node);
 out_free_fpi:
        kfree(fpi);
        return ret;
@@ -1079,6 +1082,8 @@ static int fs_enet_remove(struct platform_device *ofdev)
        of_node_put(fep->fpi->phy_node);
        if (fep->fpi->clk_per)
                clk_disable_unprepare(fep->fpi->clk_per);
+       if (of_phy_is_fixed_link(ofdev->dev.of_node))
+               of_phy_deregister_fixed_link(ofdev->dev.of_node);
        free_netdev(ndev);
        return 0;
 }
index 4b4f5bc0e2799cdaea3f1be09fc29e07cbb6b559..9061c2f82b9c504ac2df56ebce199fdf23fe503b 100644 (file)
@@ -1312,6 +1312,7 @@ static void gfar_init_addr_hash_table(struct gfar_private *priv)
  */
 static int gfar_probe(struct platform_device *ofdev)
 {
+       struct device_node *np = ofdev->dev.of_node;
        struct net_device *dev = NULL;
        struct gfar_private *priv = NULL;
        int err = 0, i;
@@ -1462,6 +1463,8 @@ static int gfar_probe(struct platform_device *ofdev)
        return 0;
 
 register_fail:
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
        unmap_group_regs(priv);
        gfar_free_rx_queues(priv);
        gfar_free_tx_queues(priv);
@@ -1474,11 +1477,16 @@ register_fail:
 static int gfar_remove(struct platform_device *ofdev)
 {
        struct gfar_private *priv = platform_get_drvdata(ofdev);
+       struct device_node *np = ofdev->dev.of_node;
 
        of_node_put(priv->phy_node);
        of_node_put(priv->tbi_node);
 
        unregister_netdev(priv->ndev);
+
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
+
        unmap_group_regs(priv);
        gfar_free_rx_queues(priv);
        gfar_free_tx_queues(priv);
index 186ef8f16c802c5b076c41f1568ef582051cb103..f76d3327945465660508af9acdaaac4b5e90a51d 100644 (file)
@@ -3868,9 +3868,8 @@ static int ucc_geth_probe(struct platform_device* ofdev)
        dev = alloc_etherdev(sizeof(*ugeth));
 
        if (dev == NULL) {
-               of_node_put(ug_info->tbi_node);
-               of_node_put(ug_info->phy_node);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_deregister_fixed_link;
        }
 
        ugeth = netdev_priv(dev);
@@ -3907,10 +3906,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
                if (netif_msg_probe(ugeth))
                        pr_err("%s: Cannot register net device, aborting\n",
                               dev->name);
-               free_netdev(dev);
-               of_node_put(ug_info->tbi_node);
-               of_node_put(ug_info->phy_node);
-               return err;
+               goto err_free_netdev;
        }
 
        mac_addr = of_get_mac_address(np);
@@ -3923,16 +3919,29 @@ static int ucc_geth_probe(struct platform_device* ofdev)
        ugeth->node = np;
 
        return 0;
+
+err_free_netdev:
+       free_netdev(dev);
+err_deregister_fixed_link:
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
+       of_node_put(ug_info->tbi_node);
+       of_node_put(ug_info->phy_node);
+
+       return err;
 }
 
 static int ucc_geth_remove(struct platform_device* ofdev)
 {
        struct net_device *dev = platform_get_drvdata(ofdev);
        struct ucc_geth_private *ugeth = netdev_priv(dev);
+       struct device_node *np = ofdev->dev.of_node;
 
        unregister_netdev(dev);
        free_netdev(dev);
        ucc_geth_memclean(ugeth);
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
        of_node_put(ugeth->ug_info->tbi_node);
        of_node_put(ugeth->ug_info->phy_node);
 
index c54c6fac0d1de065cc891fe9103bba027c6f2df8..b6ed818f78fffe21ee2b4c385c7c6222bc5df9f3 100644 (file)
@@ -332,8 +332,10 @@ struct hnae_handle *hnae_get_handle(struct device *owner_dev,
                return ERR_PTR(-ENODEV);
 
        handle = dev->ops->get_handle(dev, port_id);
-       if (IS_ERR(handle))
+       if (IS_ERR(handle)) {
+               put_device(&dev->cls_dev);
                return handle;
+       }
 
        handle->dev = dev;
        handle->owner_dev = owner_dev;
@@ -356,6 +358,8 @@ out_when_init_queue:
        for (j = i - 1; j >= 0; j--)
                hnae_fini_queue(handle->qs[j]);
 
+       put_device(&dev->cls_dev);
+
        return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL(hnae_get_handle);
@@ -377,6 +381,8 @@ void hnae_put_handle(struct hnae_handle *h)
                dev->ops->put_handle(h);
 
        module_put(dev->owner);
+
+       put_device(&dev->cls_dev);
 }
 EXPORT_SYMBOL(hnae_put_handle);
 
index 8d70377f6624cb5d1cd55ae9916af6f75ee934b4..8ea3d95fa483b9d05e4769d6a6aa66dd10ce7e15 100644 (file)
@@ -2751,6 +2751,7 @@ static const struct of_device_id g_dsaf_match[] = {
        {.compatible = "hisilicon,hns-dsaf-v2"},
        {}
 };
+MODULE_DEVICE_TABLE(of, g_dsaf_match);
 
 static struct platform_driver g_dsaf_driver = {
        .probe = hns_dsaf_probe,
index 33f4c483af0f46c6b6506bae6786833d4161fbd0..501eb2090ca62bcd118abc136e4c433bdaa38eb6 100644 (file)
@@ -563,6 +563,7 @@ static const struct of_device_id hns_mdio_match[] = {
        {.compatible = "hisilicon,hns-mdio"},
        {}
 };
+MODULE_DEVICE_TABLE(of, hns_mdio_match);
 
 static const struct acpi_device_id hns_mdio_acpi_match[] = {
        { "HISI0141", 0 },
index 54efa9a5167b86021802b98900e6ff216fa10a73..bd719e25dd76d75395711b87d792fb28ca6dd692 100644 (file)
@@ -2446,6 +2446,8 @@ static int ehea_open(struct net_device *dev)
 
        netif_info(port, ifup, dev, "enabling port\n");
 
+       netif_carrier_off(dev);
+
        ret = ehea_up(dev);
        if (!ret) {
                port_napi_enable(port);
index ebe60719e489cd1fbdc12248ee48eed6d0979fd4..a36022ba4e4232025483ec937cb894474886706a 100644 (file)
@@ -58,7 +58,7 @@ static struct kobj_type ktype_veth_pool;
 
 static const char ibmveth_driver_name[] = "ibmveth";
 static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver";
-#define ibmveth_driver_version "1.05"
+#define ibmveth_driver_version "1.06"
 
 MODULE_AUTHOR("Santiago Leon <santil@linux.vnet.ibm.com>");
 MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver");
@@ -137,6 +137,11 @@ static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
        return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK;
 }
 
+static inline int ibmveth_rxq_large_packet(struct ibmveth_adapter *adapter)
+{
+       return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_LRG_PKT;
+}
+
 static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
 {
        return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
@@ -1174,6 +1179,45 @@ map_failed:
        goto retry_bounce;
 }
 
+static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
+{
+       int offset = 0;
+
+       /* only TCP packets will be aggregated */
+       if (skb->protocol == htons(ETH_P_IP)) {
+               struct iphdr *iph = (struct iphdr *)skb->data;
+
+               if (iph->protocol == IPPROTO_TCP) {
+                       offset = iph->ihl * 4;
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+               } else {
+                       return;
+               }
+       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               struct ipv6hdr *iph6 = (struct ipv6hdr *)skb->data;
+
+               if (iph6->nexthdr == IPPROTO_TCP) {
+                       offset = sizeof(struct ipv6hdr);
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+               } else {
+                       return;
+               }
+       } else {
+               return;
+       }
+       /* if mss is not set through Large Packet bit/mss in rx buffer,
+        * expect that the mss will be written to the tcp header checksum.
+        */
+       if (lrg_pkt) {
+               skb_shinfo(skb)->gso_size = mss;
+       } else if (offset) {
+               struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset);
+
+               skb_shinfo(skb)->gso_size = ntohs(tcph->check);
+               tcph->check = 0;
+       }
+}
+
 static int ibmveth_poll(struct napi_struct *napi, int budget)
 {
        struct ibmveth_adapter *adapter =
@@ -1182,6 +1226,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
        int frames_processed = 0;
        unsigned long lpar_rc;
        struct iphdr *iph;
+       u16 mss = 0;
 
 restart_poll:
        while (frames_processed < budget) {
@@ -1199,9 +1244,21 @@ restart_poll:
                        int length = ibmveth_rxq_frame_length(adapter);
                        int offset = ibmveth_rxq_frame_offset(adapter);
                        int csum_good = ibmveth_rxq_csum_good(adapter);
+                       int lrg_pkt = ibmveth_rxq_large_packet(adapter);
 
                        skb = ibmveth_rxq_get_buffer(adapter);
 
+                       /* if the large packet bit is set in the rx queue
+                        * descriptor, the mss will be written by PHYP eight
+                        * bytes from the start of the rx buffer, which is
+                        * skb->data at this stage
+                        */
+                       if (lrg_pkt) {
+                               __be64 *rxmss = (__be64 *)(skb->data + 8);
+
+                               mss = (u16)be64_to_cpu(*rxmss);
+                       }
+
                        new_skb = NULL;
                        if (length < rx_copybreak)
                                new_skb = netdev_alloc_skb(netdev, length);
@@ -1235,11 +1292,15 @@ restart_poll:
                                        if (iph->check == 0xffff) {
                                                iph->check = 0;
                                                iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-                                               adapter->rx_large_packets++;
                                        }
                                }
                        }
 
+                       if (length > netdev->mtu + ETH_HLEN) {
+                               ibmveth_rx_mss_helper(skb, mss, lrg_pkt);
+                               adapter->rx_large_packets++;
+                       }
+
                        napi_gro_receive(napi, skb);    /* send it up */
 
                        netdev->stats.rx_packets++;
index 4eade67fe30c32a0c528631b27ab9042bd1d4caf..7acda04d034e909269bf7c75befe125313150870 100644 (file)
@@ -209,6 +209,7 @@ struct ibmveth_rx_q_entry {
 #define IBMVETH_RXQ_TOGGLE             0x80000000
 #define IBMVETH_RXQ_TOGGLE_SHIFT       31
 #define IBMVETH_RXQ_VALID              0x40000000
+#define IBMVETH_RXQ_LRG_PKT            0x04000000
 #define IBMVETH_RXQ_NO_CSUM            0x02000000
 #define IBMVETH_RXQ_CSUM_GOOD          0x01000000
 #define IBMVETH_RXQ_OFF_MASK           0x0000FFFF
index bfe17d9c022df9ac8932c1cef9e4eac94cf23d77..0fbf686f5e7c6907e74a4bd5dea9847e895be946 100644 (file)
@@ -74,7 +74,6 @@
 #include <asm/iommu.h>
 #include <linux/uaccess.h>
 #include <asm/firmware.h>
-#include <linux/seq_file.h>
 #include <linux/workqueue.h>
 
 #include "ibmvnic.h"
@@ -1190,7 +1189,7 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter
        if (!scrq)
                return NULL;
 
-       scrq->msgs = (union sub_crq *)__get_free_pages(GFP_KERNEL, 2);
+       scrq->msgs = (union sub_crq *)__get_free_pages(GFP_ATOMIC, 2);
        memset(scrq->msgs, 0, 4 * PAGE_SIZE);
        if (!scrq->msgs) {
                dev_warn(dev, "Couldn't allocate crq queue messages page\n");
@@ -1461,14 +1460,16 @@ static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter)
        return rc;
 
 req_rx_irq_failed:
-       for (j = 0; j < i; j++)
+       for (j = 0; j < i; j++) {
                free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]);
                irq_dispose_mapping(adapter->rx_scrq[j]->irq);
+       }
        i = adapter->req_tx_queues;
 req_tx_irq_failed:
-       for (j = 0; j < i; j++)
+       for (j = 0; j < i; j++) {
                free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]);
                irq_dispose_mapping(adapter->rx_scrq[j]->irq);
+       }
        release_sub_crqs_no_irqs(adapter);
        return rc;
 }
@@ -1503,9 +1504,8 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
                    adapter->max_rx_add_entries_per_subcrq > entries_page ?
                    entries_page : adapter->max_rx_add_entries_per_subcrq;
 
-               /* Choosing the maximum number of queues supported by firmware*/
-               adapter->req_tx_queues = adapter->max_tx_queues;
-               adapter->req_rx_queues = adapter->max_rx_queues;
+               adapter->req_tx_queues = adapter->opt_tx_comp_sub_queues;
+               adapter->req_rx_queues = adapter->opt_rx_comp_queues;
                adapter->req_rx_add_queues = adapter->max_rx_add_queues;
 
                adapter->req_mtu = adapter->max_mtu;
@@ -3232,6 +3232,27 @@ static void ibmvnic_free_inflight(struct ibmvnic_adapter *adapter)
        spin_unlock_irqrestore(&adapter->inflight_lock, flags);
 }
 
+static void ibmvnic_xport_event(struct work_struct *work)
+{
+       struct ibmvnic_adapter *adapter = container_of(work,
+                                                      struct ibmvnic_adapter,
+                                                      ibmvnic_xport);
+       struct device *dev = &adapter->vdev->dev;
+       long rc;
+
+       ibmvnic_free_inflight(adapter);
+       release_sub_crqs(adapter);
+       if (adapter->migrated) {
+               rc = ibmvnic_reenable_crq_queue(adapter);
+               if (rc)
+                       dev_err(dev, "Error after enable rc=%ld\n", rc);
+               adapter->migrated = false;
+               rc = ibmvnic_send_crq_init(adapter);
+               if (rc)
+                       dev_err(dev, "Error sending init rc=%ld\n", rc);
+       }
+}
+
 static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                               struct ibmvnic_adapter *adapter)
 {
@@ -3267,15 +3288,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                if (gen_crq->cmd == IBMVNIC_PARTITION_MIGRATED) {
                        dev_info(dev, "Re-enabling adapter\n");
                        adapter->migrated = true;
-                       ibmvnic_free_inflight(adapter);
-                       release_sub_crqs(adapter);
-                       rc = ibmvnic_reenable_crq_queue(adapter);
-                       if (rc)
-                               dev_err(dev, "Error after enable rc=%ld\n", rc);
-                       adapter->migrated = false;
-                       rc = ibmvnic_send_crq_init(adapter);
-                       if (rc)
-                               dev_err(dev, "Error sending init rc=%ld\n", rc);
+                       schedule_work(&adapter->ibmvnic_xport);
                } else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) {
                        dev_info(dev, "Backing device failover detected\n");
                        netif_carrier_off(netdev);
@@ -3284,8 +3297,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                        /* The adapter lost the connection */
                        dev_err(dev, "Virtual Adapter failed (rc=%d)\n",
                                gen_crq->cmd);
-                       ibmvnic_free_inflight(adapter);
-                       release_sub_crqs(adapter);
+                       schedule_work(&adapter->ibmvnic_xport);
                }
                return;
        case IBMVNIC_CRQ_CMD_RSP:
@@ -3654,6 +3666,7 @@ static void handle_crq_init_rsp(struct work_struct *work)
                goto task_failed;
 
        netdev->real_num_tx_queues = adapter->req_tx_queues;
+       netdev->mtu = adapter->req_mtu;
 
        if (adapter->failover) {
                adapter->failover = false;
@@ -3691,7 +3704,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
        struct net_device *netdev;
        unsigned char *mac_addr_p;
        struct dentry *ent;
-       char buf[16]; /* debugfs name buf */
+       char buf[17]; /* debugfs name buf */
        int rc;
 
        dev_dbg(&dev->dev, "entering ibmvnic_probe for UA 0x%x\n",
@@ -3725,6 +3738,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
        SET_NETDEV_DEV(netdev, &dev->dev);
 
        INIT_WORK(&adapter->vnic_crq_init, handle_crq_init_rsp);
+       INIT_WORK(&adapter->ibmvnic_xport, ibmvnic_xport_event);
 
        spin_lock_init(&adapter->stats_lock);
 
@@ -3792,6 +3806,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
        }
 
        netdev->real_num_tx_queues = adapter->req_tx_queues;
+       netdev->mtu = adapter->req_mtu;
 
        rc = register_netdev(netdev);
        if (rc) {
@@ -3828,6 +3843,9 @@ static int ibmvnic_remove(struct vio_dev *dev)
        if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir))
                debugfs_remove_recursive(adapter->debugfs_dir);
 
+       dma_unmap_single(&dev->dev, adapter->stats_token,
+                        sizeof(struct ibmvnic_statistics), DMA_FROM_DEVICE);
+
        if (adapter->ras_comps)
                dma_free_coherent(&dev->dev,
                                  adapter->ras_comp_num *
index bfc84c7d0e1146570d955617faf83a2643eff591..dd775d951b739eed4cd27985c055cacef0e56b6b 100644 (file)
@@ -27,7 +27,7 @@
 /**************************************************************************/
 
 #define IBMVNIC_NAME           "ibmvnic"
-#define IBMVNIC_DRIVER_VERSION "1.0"
+#define IBMVNIC_DRIVER_VERSION "1.0.1"
 #define IBMVNIC_INVALID_MAP    -1
 #define IBMVNIC_STATS_TIMEOUT  1
 /* basic structures plus 100 2k buffers */
@@ -1048,5 +1048,6 @@ struct ibmvnic_adapter {
        u8 map_id;
 
        struct work_struct vnic_crq_init;
+       struct work_struct ibmvnic_xport;
        bool failover;
 };
index 2030d7c1dc94ab01cfbb79862ff1cd8da8e73f3d..6d61e443bdf863a4fa9a71df725bf5de57a412c6 100644 (file)
@@ -92,6 +92,7 @@
 #define I40E_AQ_LEN                    256
 #define I40E_AQ_WORK_LIMIT             66 /* max number of VFs + a little */
 #define I40E_MAX_USER_PRIORITY         8
+#define I40E_DEFAULT_TRAFFIC_CLASS     BIT(0)
 #define I40E_DEFAULT_MSG_ENABLE                4
 #define I40E_QUEUE_WAIT_RETRY_LIMIT    10
 #define I40E_INT_NAME_STR_LEN          (IFNAMSIZ + 16)
index ac1faee2a5b88fe963b37d26e45ea7ff3a3d66c9..31c97e3937a4238f879ac250f96107ac01088f1c 100644 (file)
@@ -4640,29 +4640,6 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
        return num_tc;
 }
 
-/**
- * i40e_pf_get_default_tc - Get bitmap for first enabled TC
- * @pf: PF being queried
- *
- * Return a bitmap for first enabled traffic class for this PF.
- **/
-static u8 i40e_pf_get_default_tc(struct i40e_pf *pf)
-{
-       u8 enabled_tc = pf->hw.func_caps.enabled_tcmap;
-       u8 i = 0;
-
-       if (!enabled_tc)
-               return 0x1; /* TC0 */
-
-       /* Find the first enabled TC */
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               if (enabled_tc & BIT(i))
-                       break;
-       }
-
-       return BIT(i);
-}
-
 /**
  * i40e_pf_get_pf_tc_map - Get bitmap for enabled traffic classes
  * @pf: PF being queried
@@ -4673,7 +4650,7 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
 {
        /* If DCB is not enabled for this PF then just return default TC */
        if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
-               return i40e_pf_get_default_tc(pf);
+               return I40E_DEFAULT_TRAFFIC_CLASS;
 
        /* SFP mode we want PF to be enabled for all TCs */
        if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
@@ -4683,7 +4660,7 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
        if (pf->hw.func_caps.iscsi)
                return i40e_get_iscsi_tc_map(pf);
        else
-               return i40e_pf_get_default_tc(pf);
+               return I40E_DEFAULT_TRAFFIC_CLASS;
 }
 
 /**
@@ -5029,7 +5006,7 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf)
                if (v == pf->lan_vsi)
                        tc_map = i40e_pf_get_tc_map(pf);
                else
-                       tc_map = i40e_pf_get_default_tc(pf);
+                       tc_map = I40E_DEFAULT_TRAFFIC_CLASS;
 #ifdef I40E_FCOE
                if (pf->vsi[v]->type == I40E_VSI_FCOE)
                        tc_map = i40e_get_fcoe_tc_map(pf);
@@ -5717,7 +5694,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
        u8 type;
 
        /* Not DCB capable or capability disabled */
-       if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
+       if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
                return ret;
 
        /* Ignore if event is not for Nearest Bridge */
@@ -7707,6 +7684,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
                pf->flags &= ~I40E_FLAG_MSIX_ENABLED;
                kfree(pf->msix_entries);
                pf->msix_entries = NULL;
+               pci_disable_msix(pf->pdev);
                return -ENODEV;
 
        } else if (v_actual == I40E_MIN_MSIX) {
@@ -9056,7 +9034,7 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                return 0;
 
        return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode,
-                                      nlflags, 0, 0, filter_mask, NULL);
+                                      0, 0, nlflags, filter_mask, NULL);
 }
 
 /* Hardware supports L4 tunnel length of 128B (=2^7) which includes
index edc9a6ac5169328b3690672b47a699df8dc2d588..9affd7c198bd2350cadf5d96be70e00369e0976c 100644 (file)
@@ -4931,11 +4931,15 @@ static int igb_tso(struct igb_ring *tx_ring,
 
        /* initialize outer IP header fields */
        if (ip.v4->version == 4) {
+               unsigned char *csum_start = skb_checksum_start(skb);
+               unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4);
+
                /* IP header will have to cancel out any data that
                 * is not a part of the outer IP header
                 */
-               ip.v4->check = csum_fold(csum_add(lco_csum(skb),
-                                                 csum_unfold(l4.tcp->check)));
+               ip.v4->check = csum_fold(csum_partial(trans_start,
+                                                     csum_start - trans_start,
+                                                     0));
                type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
 
                ip.v4->tot_len = 0;
index 12bb877df86091f92716f1225e17a6b66bc1a4b4..7dff7f6239cd770766607102ae532c2ed9129ff2 100644 (file)
@@ -1965,11 +1965,15 @@ static int igbvf_tso(struct igbvf_ring *tx_ring,
 
        /* initialize outer IP header fields */
        if (ip.v4->version == 4) {
+               unsigned char *csum_start = skb_checksum_start(skb);
+               unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4);
+
                /* IP header will have to cancel out any data that
                 * is not a part of the outer IP header
                 */
-               ip.v4->check = csum_fold(csum_add(lco_csum(skb),
-                                                 csum_unfold(l4.tcp->check)));
+               ip.v4->check = csum_fold(csum_partial(trans_start,
+                                                     csum_start - trans_start,
+                                                     0));
                type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
 
                ip.v4->tot_len = 0;
index a244d9a67264cc49a6c7bfb8ff6f9af44a22839c..fee1f2918eadc1217cbf8fc96b438651c71dd223 100644 (file)
@@ -7277,11 +7277,15 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
 
        /* initialize outer IP header fields */
        if (ip.v4->version == 4) {
+               unsigned char *csum_start = skb_checksum_start(skb);
+               unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4);
+
                /* IP header will have to cancel out any data that
                 * is not a part of the outer IP header
                 */
-               ip.v4->check = csum_fold(csum_add(lco_csum(skb),
-                                                 csum_unfold(l4.tcp->check)));
+               ip.v4->check = csum_fold(csum_partial(trans_start,
+                                                     csum_start - trans_start,
+                                                     0));
                type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
 
                ip.v4->tot_len = 0;
@@ -9135,10 +9139,14 @@ static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
                goto fwd_add_err;
        fwd_adapter->pool = pool;
        fwd_adapter->real_adapter = adapter;
-       err = ixgbe_fwd_ring_up(vdev, fwd_adapter);
-       if (err)
-               goto fwd_add_err;
-       netif_tx_start_all_queues(vdev);
+
+       if (netif_running(pdev)) {
+               err = ixgbe_fwd_ring_up(vdev, fwd_adapter);
+               if (err)
+                       goto fwd_add_err;
+               netif_tx_start_all_queues(vdev);
+       }
+
        return fwd_adapter;
 fwd_add_err:
        /* unwind counter and free adapter struct */
index 7eaac323404990073439d243e884801bee61db3c..cbf70fe4028a8191118d8c0b41cec7d202042bc2 100644 (file)
@@ -3329,11 +3329,15 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
 
        /* initialize outer IP header fields */
        if (ip.v4->version == 4) {
+               unsigned char *csum_start = skb_checksum_start(skb);
+               unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4);
+
                /* IP header will have to cancel out any data that
                 * is not a part of the outer IP header
                 */
-               ip.v4->check = csum_fold(csum_add(lco_csum(skb),
-                                                 csum_unfold(l4.tcp->check)));
+               ip.v4->check = csum_fold(csum_partial(trans_start,
+                                                     csum_start - trans_start,
+                                                     0));
                type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
 
                ip.v4->tot_len = 0;
index 91e09d68b7e25ddd720aefdd7a79720e2e02ae4c..a167fd7ee13e0dcb36ce40fa6ba435c1883e348b 100644 (file)
@@ -704,6 +704,7 @@ ltq_etop_probe(struct platform_device *pdev)
        priv->pldata = dev_get_platdata(&pdev->dev);
        priv->netdev = dev;
        spin_lock_init(&priv->lock);
+       SET_NETDEV_DEV(dev, &pdev->dev);
 
        for (i = 0; i < MAX_DMA_CHAN; i++) {
                if (IS_TX(i))
index 55831188bc32431e935550a7da5671fa1d24d89a..5b12022adf1f74fe47411615f6f622ef91c8840c 100644 (file)
@@ -1381,6 +1381,7 @@ static unsigned int get_rx_coal(struct mv643xx_eth_private *mp)
                temp = (val & 0x003fff00) >> 8;
 
        temp *= 64000000;
+       temp += mp->t_clk / 2;
        do_div(temp, mp->t_clk);
 
        return (unsigned int)temp;
@@ -1417,6 +1418,7 @@ static unsigned int get_tx_coal(struct mv643xx_eth_private *mp)
 
        temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4;
        temp *= 64000000;
+       temp += mp->t_clk / 2;
        do_div(temp, mp->t_clk);
 
        return (unsigned int)temp;
@@ -2968,6 +2970,22 @@ static void set_params(struct mv643xx_eth_private *mp,
        mp->txq_count = pd->tx_queue_count ? : 1;
 }
 
+static int get_phy_mode(struct mv643xx_eth_private *mp)
+{
+       struct device *dev = mp->dev->dev.parent;
+       int iface = -1;
+
+       if (dev->of_node)
+               iface = of_get_phy_mode(dev->of_node);
+
+       /* Historical default if unspecified. We could also read/write
+        * the interface state in the PSC1
+        */
+       if (iface < 0)
+               iface = PHY_INTERFACE_MODE_GMII;
+       return iface;
+}
+
 static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,
                                   int phy_addr)
 {
@@ -2994,7 +3012,7 @@ static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,
                                "orion-mdio-mii", addr);
 
                phydev = phy_connect(mp->dev, phy_id, mv643xx_eth_adjust_link,
-                               PHY_INTERFACE_MODE_GMII);
+                                    get_phy_mode(mp));
                if (!IS_ERR(phydev)) {
                        phy_addr_set(mp, addr);
                        break;
@@ -3090,6 +3108,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        if (!dev)
                return -ENOMEM;
 
+       SET_NETDEV_DEV(dev, &pdev->dev);
        mp = netdev_priv(dev);
        platform_set_drvdata(pdev, mp);
 
@@ -3129,7 +3148,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        if (pd->phy_node) {
                mp->phy = of_phy_connect(mp->dev, pd->phy_node,
                                         mv643xx_eth_adjust_link, 0,
-                                        PHY_INTERFACE_MODE_GMII);
+                                        get_phy_mode(mp));
                if (!mp->phy)
                        err = -ENODEV;
                else
@@ -3187,8 +3206,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        dev->priv_flags |= IFF_UNICAST_FLT;
        dev->gso_max_segs = MV643XX_MAX_TSO_SEGS;
 
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
        if (mp->shared->win_protect)
                wrl(mp, WINDOW_PROTECT(mp->port_num), mp->shared->win_protect);
 
index 5cb07c2017bfa897248d589fda460ca68e770114..707bc4680b9bd37215e2a75bdeac42cf08f31212 100644 (file)
@@ -4151,7 +4151,7 @@ static int mvneta_probe(struct platform_device *pdev)
        dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
        dev->hw_features |= dev->features;
        dev->vlan_features |= dev->features;
-       dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE;
+       dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
        dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
 
        err = register_netdev(dev);
@@ -4191,6 +4191,8 @@ err_clk:
        clk_disable_unprepare(pp->clk);
 err_put_phy_node:
        of_node_put(phy_node);
+       if (of_phy_is_fixed_link(dn))
+               of_phy_deregister_fixed_link(dn);
 err_free_irq:
        irq_dispose_mapping(dev->irq);
 err_free_netdev:
@@ -4202,6 +4204,7 @@ err_free_netdev:
 static int mvneta_remove(struct platform_device *pdev)
 {
        struct net_device  *dev = platform_get_drvdata(pdev);
+       struct device_node *dn = pdev->dev.of_node;
        struct mvneta_port *pp = netdev_priv(dev);
 
        unregister_netdev(dev);
@@ -4209,6 +4212,8 @@ static int mvneta_remove(struct platform_device *pdev)
        clk_disable_unprepare(pp->clk);
        free_percpu(pp->ports);
        free_percpu(pp->stats);
+       if (of_phy_is_fixed_link(dn))
+               of_phy_deregister_fixed_link(dn);
        irq_dispose_mapping(dev->irq);
        of_node_put(pp->phy_node);
        free_netdev(dev);
index 60227a3452a40d00014a2f7d5584f3b518785455..1026c452e39de4ccd1e82f18ed6284a1d51a4ea0 100644 (file)
@@ -3293,7 +3293,7 @@ static void mvpp2_cls_init(struct mvpp2 *priv)
        mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
 
        /* Clear classifier flow table */
-       memset(&fe.data, 0, MVPP2_CLS_FLOWS_TBL_DATA_WORDS);
+       memset(&fe.data, 0, sizeof(fe.data));
        for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) {
                fe.index = index;
                mvpp2_cls_flow_write(priv, &fe);
index f05ea56dcff2cdecee79e21ac38c1c9623378912..941c8e2c944e11d349937c89cc143eb94cb78fc7 100644 (file)
@@ -5220,6 +5220,19 @@ static SIMPLE_DEV_PM_OPS(sky2_pm_ops, sky2_suspend, sky2_resume);
 
 static void sky2_shutdown(struct pci_dev *pdev)
 {
+       struct sky2_hw *hw = pci_get_drvdata(pdev);
+       int port;
+
+       for (port = 0; port < hw->ports; port++) {
+               struct net_device *ndev = hw->dev[port];
+
+               rtnl_lock();
+               if (netif_running(ndev)) {
+                       dev_close(ndev);
+                       netif_device_detach(ndev);
+               }
+               rtnl_unlock();
+       }
        sky2_suspend(&pdev->dev);
        pci_wake_from_d3(pdev, device_may_wakeup(&pdev->dev));
        pci_set_power_state(pdev, PCI_D3hot);
index 4a62ffd7729d0327f35b16d4a5b4e3dc89adbb01..86a89cbd3ec95c8e01eba987799bbab196c53eaf 100644 (file)
@@ -318,6 +318,8 @@ static int mtk_phy_connect(struct net_device *dev)
        return 0;
 
 err_phy:
+       if (of_phy_is_fixed_link(mac->of_node))
+               of_phy_deregister_fixed_link(mac->of_node);
        of_node_put(np);
        dev_err(eth->dev, "%s: invalid phy\n", __func__);
        return -EINVAL;
@@ -1923,6 +1925,8 @@ static void mtk_uninit(struct net_device *dev)
        struct mtk_eth *eth = mac->hw;
 
        phy_disconnect(dev->phydev);
+       if (of_phy_is_fixed_link(mac->of_node))
+               of_phy_deregister_fixed_link(mac->of_node);
        mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0);
        mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0);
 }
index b1cef7a0f7ca62fe982ddf507a8cc4f2900e3243..e36bebcab3f228794b462fd834e592f07c651ad4 100644 (file)
@@ -2469,6 +2469,7 @@ err_comm_admin:
        kfree(priv->mfunc.master.slave_state);
 err_comm:
        iounmap(priv->mfunc.comm);
+       priv->mfunc.comm = NULL;
 err_vhcr:
        dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
                          priv->mfunc.vhcr,
@@ -2537,6 +2538,13 @@ void mlx4_report_internal_err_comm_event(struct mlx4_dev *dev)
        int slave;
        u32 slave_read;
 
+       /* If the comm channel has not yet been initialized,
+        * skip reporting the internal error event to all
+        * the communication channels.
+        */
+       if (!priv->mfunc.comm)
+               return;
+
        /* Report an internal error event to all
         * communication channels.
         */
@@ -2571,6 +2579,7 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev)
        }
 
        iounmap(priv->mfunc.comm);
+       priv->mfunc.comm = NULL;
 }
 
 void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask)
index 08fc5fc56d43b489ab6a8502012b5cad925a0e7b..a5fc46bbcbe224373b768633f600f3d66d4865d5 100644 (file)
@@ -245,8 +245,11 @@ static u32 freq_to_shift(u16 freq)
 {
        u32 freq_khz = freq * 1000;
        u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC;
+       u64 tmp_rounded =
+               roundup_pow_of_two(max_val_cycles) > max_val_cycles ?
+               roundup_pow_of_two(max_val_cycles) - 1 : UINT_MAX;
        u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ?
-               max_val_cycles : roundup_pow_of_two(max_val_cycles) - 1;
+               max_val_cycles : tmp_rounded;
        /* calculate max possible multiplier in order to fit in 64bit */
        u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded);
 
index 132cea655920d636c2e22fd2f110d163a421b8f3..e3be7e44ff51fcc2947df46f2ff9ff7326e42eb6 100644 (file)
@@ -127,7 +127,15 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
                /* For TX we use the same irq per
                ring we assigned for the RX    */
                struct mlx4_en_cq *rx_cq;
-
+               int xdp_index;
+
+               /* The xdp tx irq must align with the rx ring that forwards to
+                * it, so reindex these from 0. This should only happen when
+                * tx_ring_num is not a multiple of rx_ring_num.
+                */
+               xdp_index = (priv->xdp_ring_num - priv->tx_ring_num) + cq_idx;
+               if (xdp_index >= 0)
+                       cq_idx = xdp_index;
                cq_idx = cq_idx % priv->rx_ring_num;
                rx_cq = priv->rx_cq[cq_idx];
                cq->vector = rx_cq->vector;
index 7e703bed7b820950f6ecee51dc25b2c29c8b2eca..fb8bb027b69c3332ef23d4b59f9288103a5b12ba 100644 (file)
@@ -129,6 +129,9 @@ static enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto)
        }
 };
 
+/* Must not acquire state_lock, as its corresponding work_sync
+ * is done under it.
+ */
 static void mlx4_en_filter_work(struct work_struct *work)
 {
        struct mlx4_en_filter *filter = container_of(work,
@@ -1733,6 +1736,13 @@ int mlx4_en_start_port(struct net_device *dev)
                udp_tunnel_get_rx_info(dev);
 
        priv->port_up = true;
+
+       /* Process all completions if exist to prevent
+        * the queues freezing if they are full
+        */
+       for (i = 0; i < priv->rx_ring_num; i++)
+               napi_schedule(&priv->rx_cq[i]->napi);
+
        netif_tx_start_all_queues(dev);
        netif_device_attach(dev);
 
@@ -1910,8 +1920,9 @@ static void mlx4_en_clear_stats(struct net_device *dev)
        struct mlx4_en_dev *mdev = priv->mdev;
        int i;
 
-       if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1))
-               en_dbg(HW, priv, "Failed dumping statistics\n");
+       if (!mlx4_is_slave(mdev->dev))
+               if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1))
+                       en_dbg(HW, priv, "Failed dumping statistics\n");
 
        memset(&priv->pstats, 0, sizeof(priv->pstats));
        memset(&priv->pkstats, 0, sizeof(priv->pkstats));
@@ -2068,13 +2079,6 @@ err:
        return -ENOMEM;
 }
 
-static void mlx4_en_shutdown(struct net_device *dev)
-{
-       rtnl_lock();
-       netif_device_detach(dev);
-       mlx4_en_close(dev);
-       rtnl_unlock();
-}
 
 static int mlx4_en_copy_priv(struct mlx4_en_priv *dst,
                             struct mlx4_en_priv *src,
@@ -2151,8 +2155,6 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
-       bool shutdown = mdev->dev->persist->interface_state &
-                                           MLX4_INTERFACE_STATE_SHUTDOWN;
 
        en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port);
 
@@ -2160,10 +2162,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
        if (priv->registered) {
                devlink_port_type_clear(mlx4_get_devlink_port(mdev->dev,
                                                              priv->port));
-               if (shutdown)
-                       mlx4_en_shutdown(dev);
-               else
-                       unregister_netdev(dev);
+               unregister_netdev(dev);
        }
 
        if (priv->allocated)
@@ -2181,19 +2180,18 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
        mutex_lock(&mdev->state_lock);
        mdev->pndev[priv->port] = NULL;
        mdev->upper[priv->port] = NULL;
-       mutex_unlock(&mdev->state_lock);
 
 #ifdef CONFIG_RFS_ACCEL
        mlx4_en_cleanup_filters(priv);
 #endif
 
        mlx4_en_free_resources(priv);
+       mutex_unlock(&mdev->state_lock);
 
        kfree(priv->tx_ring);
        kfree(priv->tx_cq);
 
-       if (!shutdown)
-               free_netdev(dev);
+       free_netdev(dev);
 }
 
 static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
index 5aa8b751f4170c782f13a3d0ef6f3b557b21168d..59473a0ebcdfeaa33dc4e34d45ecb8b444a6e8db 100644 (file)
@@ -166,7 +166,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
                return PTR_ERR(mailbox);
        err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0,
                           MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
-                          MLX4_CMD_WRAPPED);
+                          MLX4_CMD_NATIVE);
        if (err)
                goto out;
 
@@ -322,7 +322,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
                err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma,
                                   in_mod | MLX4_DUMP_ETH_STATS_FLOW_CONTROL,
                                   0, MLX4_CMD_DUMP_ETH_STATS,
-                                  MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
+                                  MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
                if (err)
                        goto out;
        }
index b66e03d9711f945fe06827ed480258a78ce26833..c06346a82496876379ff5771e9ae7a03b4ad10a0 100644 (file)
@@ -118,6 +118,29 @@ mlx4_en_test_loopback_exit:
        return !loopback_ok;
 }
 
+static int mlx4_en_test_interrupts(struct mlx4_en_priv *priv)
+{
+       struct mlx4_en_dev *mdev = priv->mdev;
+       int err = 0;
+       int i = 0;
+
+       err = mlx4_test_async(mdev->dev);
+       /* When not in MSI_X or slave, test only async */
+       if (!(mdev->dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(mdev->dev))
+               return err;
+
+       /* A loop over all completion vectors of current port,
+        * for each vector check whether it works by mapping command
+        * completions to that vector and performing a NOP command
+        */
+       for (i = 0; i < priv->rx_ring_num; i++) {
+               err = mlx4_test_interrupt(mdev->dev, priv->rx_cq[i]->vector);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
 
 static int mlx4_en_test_link(struct mlx4_en_priv *priv)
 {
@@ -151,7 +174,6 @@ static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
 void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_en_dev *mdev = priv->mdev;
        int i, carrier_ok;
 
        memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST);
@@ -177,7 +199,7 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
                        netif_carrier_on(dev);
 
        }
-       buf[0] = mlx4_test_interrupts(mdev->dev);
+       buf[0] = mlx4_en_test_interrupts(priv);
        buf[1] = mlx4_en_test_link(priv);
        buf[2] = mlx4_en_test_speed(priv);
 
index cf8f8a72a80154c19a6ccb9ca807499491ccebd9..cd3638e6fe25b2f8db4ea5e771535df51652faae 100644 (file)
@@ -1361,53 +1361,49 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
        kfree(priv->eq_table.uar_map);
 }
 
-/* A test that verifies that we can accept interrupts on all
- * the irq vectors of the device.
+/* A test that verifies that we can accept interrupts
+ * on the vector allocated for asynchronous events
+ */
+int mlx4_test_async(struct mlx4_dev *dev)
+{
+       return mlx4_NOP(dev);
+}
+EXPORT_SYMBOL(mlx4_test_async);
+
+/* A test that verifies that we can accept interrupts
+ * on the given irq vector of the tested port.
  * Interrupts are checked using the NOP command.
  */
-int mlx4_test_interrupts(struct mlx4_dev *dev)
+int mlx4_test_interrupt(struct mlx4_dev *dev, int vector)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int i;
        int err;
 
-       err = mlx4_NOP(dev);
-       /* When not in MSI_X, there is only one irq to check */
-       if (!(dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(dev))
-               return err;
-
-       /* A loop over all completion vectors, for each vector we will check
-        * whether it works by mapping command completions to that vector
-        * and performing a NOP command
-        */
-       for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) {
-               /* Make sure request_irq was called */
-               if (!priv->eq_table.eq[i].have_irq)
-                       continue;
-
-               /* Temporary use polling for command completions */
-               mlx4_cmd_use_polling(dev);
-
-               /* Map the new eq to handle all asynchronous events */
-               err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0,
-                                 priv->eq_table.eq[i].eqn);
-               if (err) {
-                       mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
-                       mlx4_cmd_use_events(dev);
-                       break;
-               }
+       /* Temporary use polling for command completions */
+       mlx4_cmd_use_polling(dev);
 
-               /* Go back to using events */
-               mlx4_cmd_use_events(dev);
-               err = mlx4_NOP(dev);
+       /* Map the new eq to handle all asynchronous events */
+       err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0,
+                         priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn);
+       if (err) {
+               mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
+               goto out;
        }
 
+       /* Go back to using events */
+       mlx4_cmd_use_events(dev);
+       err = mlx4_NOP(dev);
+
        /* Return to default */
+       mlx4_cmd_use_polling(dev);
+out:
        mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0,
                    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
+       mlx4_cmd_use_events(dev);
+
        return err;
 }
-EXPORT_SYMBOL(mlx4_test_interrupts);
+EXPORT_SYMBOL(mlx4_test_interrupt);
 
 bool mlx4_is_eq_vector_valid(struct mlx4_dev *dev, u8 port, int vector)
 {
index c41ab31a39f8c93d3caba280510b8a73413c7485..84bab9f0732ea239bce5adaac7eb52d0298cc751 100644 (file)
@@ -49,9 +49,9 @@ enum {
 extern void __buggy_use_of_MLX4_GET(void);
 extern void __buggy_use_of_MLX4_PUT(void);
 
-static bool enable_qos = true;
+static bool enable_qos;
 module_param(enable_qos, bool, 0444);
-MODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: on)");
+MODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: off)");
 
 #define MLX4_GET(dest, source, offset)                               \
        do {                                                          \
index 7183ac4135d2f97dbb1e7b63f2d57db4c95a5d0c..75d07fa9d0b1bb50f595adf9f65cf4dd9b8e4683 100644 (file)
@@ -1102,6 +1102,14 @@ static int __set_port_type(struct mlx4_port_info *info,
        int i;
        int err = 0;
 
+       if ((port_type & mdev->caps.supported_type[info->port]) != port_type) {
+               mlx4_err(mdev,
+                        "Requested port type for port %d is not supported on this HCA\n",
+                        info->port);
+               err = -EINVAL;
+               goto err_sup;
+       }
+
        mlx4_stop_sense(mdev);
        mutex_lock(&priv->port_mutex);
        info->tmp_type = port_type;
@@ -1147,7 +1155,7 @@ static int __set_port_type(struct mlx4_port_info *info,
 out:
        mlx4_start_sense(mdev);
        mutex_unlock(&priv->port_mutex);
-
+err_sup:
        return err;
 }
 
@@ -4139,11 +4147,8 @@ static void mlx4_shutdown(struct pci_dev *pdev)
 
        mlx4_info(persist->dev, "mlx4_shutdown was called\n");
        mutex_lock(&persist->interface_state_mutex);
-       if (persist->interface_state & MLX4_INTERFACE_STATE_UP) {
-               /* Notify mlx4 clients that the kernel is being shut down */
-               persist->interface_state |= MLX4_INTERFACE_STATE_SHUTDOWN;
+       if (persist->interface_state & MLX4_INTERFACE_STATE_UP)
                mlx4_unload_one(pdev);
-       }
        mutex_unlock(&persist->interface_state_mutex);
 }
 
index 94b891c118c135d3597d90ba3ec9a34d049458ee..1a670b68155550fe9f61fb2bc2c7a3688391249c 100644 (file)
@@ -1457,7 +1457,12 @@ EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
 int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
                                u32 qpn, enum mlx4_net_trans_promisc_mode mode)
 {
-       struct mlx4_net_trans_rule rule;
+       struct mlx4_net_trans_rule rule = {
+               .queue_mode = MLX4_NET_TRANS_Q_FIFO,
+               .exclusive = 0,
+               .allow_loopback = 1,
+       };
+
        u64 *regid_p;
 
        switch (mode) {
index e4878f31e45d7578e4b5f86cfc1cbe4004ffdbac..88ee7d8a59231a47d6b7aca2006f9780dbefa578 100644 (file)
@@ -145,9 +145,10 @@ enum mlx4_resource {
        RES_MTT,
        RES_MAC,
        RES_VLAN,
-       RES_EQ,
+       RES_NPORT_ID,
        RES_COUNTER,
        RES_FS_RULE,
+       RES_EQ,
        MLX4_NUM_OF_RESOURCE_TYPE
 };
 
@@ -1329,8 +1330,6 @@ int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
                               struct mlx4_cmd_info *cmd);
 int mlx4_common_set_vlan_fltr(struct mlx4_dev *dev, int function,
                                     int port, void *buf);
-int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, u32 in_mod,
-                               struct mlx4_cmd_mailbox *outbox);
 int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
                                   struct mlx4_vhcr *vhcr,
                                   struct mlx4_cmd_mailbox *inbox,
index c5b2064297a19b0dde2640764acb4216343633f1..b656dd5772e5b9ae3412d11dc8791c49fb10a78f 100644 (file)
@@ -1728,24 +1728,13 @@ int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
        return err;
 }
 
-int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave,
-                              u32 in_mod, struct mlx4_cmd_mailbox *outbox)
-{
-       return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0,
-                           MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
-                           MLX4_CMD_NATIVE);
-}
-
 int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
                                struct mlx4_vhcr *vhcr,
                                struct mlx4_cmd_mailbox *inbox,
                                struct mlx4_cmd_mailbox *outbox,
                                struct mlx4_cmd_info *cmd)
 {
-       if (slave != dev->caps.function)
-               return 0;
-       return mlx4_common_dump_eth_stats(dev, slave,
-                                         vhcr->in_modifier, outbox);
+       return 0;
 }
 
 int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
index 84d7857ccc271415f8caa448b2710a3d22b92a77..c548beaaf9109e376933660dffb39632622dbfc9 100644 (file)
@@ -1605,13 +1605,14 @@ static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index,
                        r->com.from_state = r->com.state;
                        r->com.to_state = state;
                        r->com.state = RES_EQ_BUSY;
-                       if (eq)
-                               *eq = r;
                }
        }
 
        spin_unlock_irq(mlx4_tlock(dev));
 
+       if (!err && eq)
+               *eq = r;
+
        return err;
 }
 
index aae46884bf93c949325e4bba26316cb9f69e078a..521cfdb7d11e75cdf9b4ebca53b55a60b7f72825 100644 (file)
@@ -18,8 +18,6 @@ config MLX5_CORE_EN
        default n
        ---help---
          Ethernet support in Mellanox Technologies ConnectX-4 NIC.
-         Ethernet and Infiniband support in ConnectX-4 are currently mutually
-         exclusive.
 
 config MLX5_CORE_EN_DCB
        bool "Data Center Bridging (DCB) Support"
index 6cb38304669f6e5618edfea860a8c8d5f49e5c54..2c6e3c7b7417943b643f21cd3e7d25ebd0061d9a 100644 (file)
 
 #include "mlx5_core.h"
 
+struct mlx5_db_pgdir {
+       struct list_head        list;
+       unsigned long          *bitmap;
+       __be32                 *db_page;
+       dma_addr_t              db_dma;
+};
+
 /* Handling for queue buffers -- we allocate a bunch of memory and
  * register it in a memory region at HCA virtual address 0.
  */
@@ -102,17 +109,28 @@ EXPORT_SYMBOL_GPL(mlx5_buf_free);
 static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev,
                                                 int node)
 {
+       u32 db_per_page = PAGE_SIZE / cache_line_size();
        struct mlx5_db_pgdir *pgdir;
 
        pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL);
        if (!pgdir)
                return NULL;
 
-       bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE);
+       pgdir->bitmap = kcalloc(BITS_TO_LONGS(db_per_page),
+                               sizeof(unsigned long),
+                               GFP_KERNEL);
+
+       if (!pgdir->bitmap) {
+               kfree(pgdir);
+               return NULL;
+       }
+
+       bitmap_fill(pgdir->bitmap, db_per_page);
 
        pgdir->db_page = mlx5_dma_zalloc_coherent_node(dev, PAGE_SIZE,
                                                       &pgdir->db_dma, node);
        if (!pgdir->db_page) {
+               kfree(pgdir->bitmap);
                kfree(pgdir);
                return NULL;
        }
@@ -123,18 +141,19 @@ static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev,
 static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir,
                                    struct mlx5_db *db)
 {
+       u32 db_per_page = PAGE_SIZE / cache_line_size();
        int offset;
        int i;
 
-       i = find_first_bit(pgdir->bitmap, MLX5_DB_PER_PAGE);
-       if (i >= MLX5_DB_PER_PAGE)
+       i = find_first_bit(pgdir->bitmap, db_per_page);
+       if (i >= db_per_page)
                return -ENOMEM;
 
        __clear_bit(i, pgdir->bitmap);
 
        db->u.pgdir = pgdir;
        db->index   = i;
-       offset = db->index * L1_CACHE_BYTES;
+       offset = db->index * cache_line_size();
        db->db      = pgdir->db_page + offset / sizeof(*pgdir->db_page);
        db->dma     = pgdir->db_dma  + offset;
 
@@ -181,14 +200,16 @@ EXPORT_SYMBOL_GPL(mlx5_db_alloc);
 
 void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db)
 {
+       u32 db_per_page = PAGE_SIZE / cache_line_size();
        mutex_lock(&dev->priv.pgdir_mutex);
 
        __set_bit(db->index, db->u.pgdir->bitmap);
 
-       if (bitmap_full(db->u.pgdir->bitmap, MLX5_DB_PER_PAGE)) {
+       if (bitmap_full(db->u.pgdir->bitmap, db_per_page)) {
                dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
                                  db->u.pgdir->db_page, db->u.pgdir->db_dma);
                list_del(&db->u.pgdir->list);
+               kfree(db->u.pgdir->bitmap);
                kfree(db->u.pgdir);
        }
 
index 1e639f88602165fcb4f4454cf6a54148372e3235..bfe410e8a469ee06152f36d63cbb68e8656a861d 100644 (file)
@@ -268,11 +268,6 @@ static void dump_buf(void *buf, int size, int data_only, int offset)
                pr_debug("\n");
 }
 
-enum {
-       MLX5_DRIVER_STATUS_ABORTED = 0xfe,
-       MLX5_DRIVER_SYND = 0xbadd00de,
-};
-
 static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
                                       u32 *synd, u8 *status)
 {
index 460363b66cb1ca02ad0dc7117f8e3bab868f3d9a..71382df59fc09b805755f06d492fb794a0d13383 100644 (file)
@@ -85,6 +85,9 @@
 #define MLX5_MPWRQ_SMALL_PACKET_THRESHOLD      (128)
 
 #define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ                 (64 * 1024)
+#define MLX5E_DEFAULT_LRO_TIMEOUT                       32
+#define MLX5E_LRO_TIMEOUT_ARR_SIZE                      4
+
 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC      0x10
 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE 0x3
 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS      0x20
@@ -221,6 +224,7 @@ struct mlx5e_params {
        struct ieee_ets ets;
 #endif
        bool rx_am_enabled;
+       u32 lro_timeout;
 };
 
 struct mlx5e_tstamp {
@@ -237,7 +241,7 @@ struct mlx5e_tstamp {
 };
 
 enum {
-       MLX5E_RQ_STATE_FLUSH,
+       MLX5E_RQ_STATE_ENABLED,
        MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS,
        MLX5E_RQ_STATE_AM,
 };
@@ -390,7 +394,7 @@ struct mlx5e_sq_dma {
 };
 
 enum {
-       MLX5E_SQ_STATE_FLUSH,
+       MLX5E_SQ_STATE_ENABLED,
        MLX5E_SQ_STATE_BF_ENABLE,
 };
 
@@ -888,5 +892,6 @@ int mlx5e_attach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
 void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
 struct rtnl_link_stats64 *
 mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
+u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout);
 
 #endif /* __MLX5_EN_H__ */
index 7eaf38020a8fe19afcab67dd8c582392522ecc1f..246d98ebb58890c33005ba7d7abab5743e1b45d9 100644 (file)
@@ -759,6 +759,7 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
        if (err)
                goto err_destroy_rq;
 
+       set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
        err = mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY);
        if (err)
                goto err_disable_rq;
@@ -773,6 +774,7 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
        return 0;
 
 err_disable_rq:
+       clear_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
        mlx5e_disable_rq(rq);
 err_destroy_rq:
        mlx5e_destroy_rq(rq);
@@ -782,7 +784,7 @@ err_destroy_rq:
 
 static void mlx5e_close_rq(struct mlx5e_rq *rq)
 {
-       set_bit(MLX5E_RQ_STATE_FLUSH, &rq->state);
+       clear_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
        napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */
        cancel_work_sync(&rq->am.work);
 
@@ -1006,7 +1008,6 @@ static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param)
        MLX5_SET(sqc,  sqc, min_wqe_inline_mode, sq->min_inline_mode);
        MLX5_SET(sqc,  sqc, state,              MLX5_SQC_STATE_RST);
        MLX5_SET(sqc,  sqc, tis_lst_sz, param->type == MLX5E_SQ_ICO ? 0 : 1);
-       MLX5_SET(sqc,  sqc, flush_in_error_en,  1);
 
        MLX5_SET(wq,   wq, wq_type,       MLX5_WQ_TYPE_CYCLIC);
        MLX5_SET(wq,   wq, uar_page,      sq->uar.index);
@@ -1083,6 +1084,7 @@ static int mlx5e_open_sq(struct mlx5e_channel *c,
        if (err)
                goto err_destroy_sq;
 
+       set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
        err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY,
                              false, 0);
        if (err)
@@ -1096,6 +1098,7 @@ static int mlx5e_open_sq(struct mlx5e_channel *c,
        return 0;
 
 err_disable_sq:
+       clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
        mlx5e_disable_sq(sq);
 err_destroy_sq:
        mlx5e_destroy_sq(sq);
@@ -1112,7 +1115,7 @@ static inline void netif_tx_disable_queue(struct netdev_queue *txq)
 
 static void mlx5e_close_sq(struct mlx5e_sq *sq)
 {
-       set_bit(MLX5E_SQ_STATE_FLUSH, &sq->state);
+       clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
        /* prevent netif_tx_wake_queue */
        napi_synchronize(&sq->channel->napi);
 
@@ -1445,6 +1448,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
        c->netdev   = priv->netdev;
        c->mkey_be  = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key);
        c->num_tc   = priv->params.num_tc;
+       c->xdp      = !!priv->xdp_prog;
 
        if (priv->params.rx_am_enabled)
                rx_cq_profile = mlx5e_am_get_def_profile(priv->params.rx_cq_period_mode);
@@ -1468,6 +1472,12 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
        if (err)
                goto err_close_tx_cqs;
 
+       /* XDP SQ CQ params are same as normal TXQ sq CQ params */
+       err = c->xdp ? mlx5e_open_cq(c, &cparam->tx_cq, &c->xdp_sq.cq,
+                                    priv->params.tx_cq_moderation) : 0;
+       if (err)
+               goto err_close_rx_cq;
+
        napi_enable(&c->napi);
 
        err = mlx5e_open_sq(c, 0, &cparam->icosq, &c->icosq);
@@ -1488,21 +1498,10 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
                }
        }
 
-       if (priv->xdp_prog) {
-               /* XDP SQ CQ params are same as normal TXQ sq CQ params */
-               err = mlx5e_open_cq(c, &cparam->tx_cq, &c->xdp_sq.cq,
-                                   priv->params.tx_cq_moderation);
-               if (err)
-                       goto err_close_sqs;
-
-               err = mlx5e_open_sq(c, 0, &cparam->xdp_sq, &c->xdp_sq);
-               if (err) {
-                       mlx5e_close_cq(&c->xdp_sq.cq);
-                       goto err_close_sqs;
-               }
-       }
+       err = c->xdp ? mlx5e_open_sq(c, 0, &cparam->xdp_sq, &c->xdp_sq) : 0;
+       if (err)
+               goto err_close_sqs;
 
-       c->xdp = !!priv->xdp_prog;
        err = mlx5e_open_rq(c, &cparam->rq, &c->rq);
        if (err)
                goto err_close_xdp_sq;
@@ -1512,7 +1511,8 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
 
        return 0;
 err_close_xdp_sq:
-       mlx5e_close_sq(&c->xdp_sq);
+       if (c->xdp)
+               mlx5e_close_sq(&c->xdp_sq);
 
 err_close_sqs:
        mlx5e_close_sqs(c);
@@ -1522,6 +1522,10 @@ err_close_icosq:
 
 err_disable_napi:
        napi_disable(&c->napi);
+       if (c->xdp)
+               mlx5e_close_cq(&c->xdp_sq.cq);
+
+err_close_rx_cq:
        mlx5e_close_cq(&c->rq.cq);
 
 err_close_tx_cqs:
@@ -1971,9 +1975,7 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv)
        MLX5_SET(tirc, tirc, lro_max_ip_payload_size,
                 (priv->params.lro_wqe_sz -
                  ROUGH_MAX_L2_L3_HDR_SZ) >> 8);
-       MLX5_SET(tirc, tirc, lro_timeout_period_usecs,
-                MLX5_CAP_ETH(priv->mdev,
-                             lro_timer_supported_periods[2]));
+       MLX5_SET(tirc, tirc, lro_timeout_period_usecs, priv->params.lro_timeout);
 }
 
 void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
@@ -3093,7 +3095,7 @@ static void mlx5e_tx_timeout(struct net_device *dev)
                if (!netif_xmit_stopped(netdev_get_tx_queue(dev, i)))
                        continue;
                sched_work = true;
-               set_bit(MLX5E_SQ_STATE_FLUSH, &sq->state);
+               clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
                netdev_err(dev, "TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x\n",
                           i, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc);
        }
@@ -3148,13 +3150,13 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
        for (i = 0; i < priv->params.num_channels; i++) {
                struct mlx5e_channel *c = priv->channel[i];
 
-               set_bit(MLX5E_RQ_STATE_FLUSH, &c->rq.state);
+               clear_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
                napi_synchronize(&c->napi);
                /* prevent mlx5e_poll_rx_cq from accessing rq->xdp_prog */
 
                old_prog = xchg(&c->rq.xdp_prog, prog);
 
-               clear_bit(MLX5E_RQ_STATE_FLUSH, &c->rq.state);
+               set_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
                /* napi_schedule in case we have missed anything */
                set_bit(MLX5E_CHANNEL_NAPI_SCHED, &c->flags);
                napi_schedule(&c->napi);
@@ -3401,6 +3403,18 @@ static void mlx5e_query_min_inline(struct mlx5_core_dev *mdev,
        }
 }
 
+u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout)
+{
+       int i;
+
+       /* The supported periods are organized in ascending order */
+       for (i = 0; i < MLX5E_LRO_TIMEOUT_ARR_SIZE - 1; i++)
+               if (MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]) >= wanted_timeout)
+                       break;
+
+       return MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]);
+}
+
 static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
                                        struct net_device *netdev,
                                        const struct mlx5e_profile *profile,
@@ -3419,6 +3433,9 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
        priv->profile                      = profile;
        priv->ppriv                        = ppriv;
 
+       priv->params.lro_timeout =
+               mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
+
        priv->params.log_sq_size = MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
 
        /* set CQE compression */
@@ -4035,7 +4052,6 @@ void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv)
        const struct mlx5e_profile *profile = priv->profile;
        struct net_device *netdev = priv->netdev;
 
-       unregister_netdev(netdev);
        destroy_workqueue(priv->wq);
        if (profile->cleanup)
                profile->cleanup(priv);
@@ -4052,6 +4068,7 @@ static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv)
        for (vport = 1; vport < total_vfs; vport++)
                mlx5_eswitch_unregister_vport_rep(esw, vport);
 
+       unregister_netdev(priv->netdev);
        mlx5e_detach(mdev, vpriv);
        mlx5e_destroy_netdev(mdev, priv);
 }
index 3c97da103d30e8abd0adcd2bf8b5bcb021d517cd..bf1c09ca73c03eb93d65f24ffeed1b1d04a2bb88 100644 (file)
@@ -308,7 +308,7 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
        netdev->switchdev_ops = &mlx5e_rep_switchdev_ops;
 #endif
 
-       netdev->features         |= NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_TC;
+       netdev->features         |= NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_TC | NETIF_F_NETNS_LOCAL;
        netdev->hw_features      |= NETIF_F_HW_TC;
 
        eth_hw_addr_random(netdev);
@@ -457,6 +457,7 @@ void mlx5e_vport_rep_unload(struct mlx5_eswitch *esw,
        struct mlx5e_priv *priv = rep->priv_data;
        struct net_device *netdev = priv->netdev;
 
+       unregister_netdev(netdev);
        mlx5e_detach_netdev(esw->dev, netdev);
        mlx5e_destroy_netdev(esw->dev, priv);
 }
index c6de6fba5843e08a2b92e73fc6549369b48096da..33495d88aeb21469861fd2a9e22463cabe75e9b2 100644 (file)
@@ -340,7 +340,7 @@ static inline void mlx5e_post_umr_wqe(struct mlx5e_rq *rq, u16 ix)
        while ((pi = (sq->pc & wq->sz_m1)) > sq->edge) {
                sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_NOP;
                sq->db.ico_wqe[pi].num_wqebbs = 1;
-               mlx5e_send_nop(sq, true);
+               mlx5e_send_nop(sq, false);
        }
 
        wqe = mlx5_wq_cyc_get_wqe(wq, pi);
@@ -412,7 +412,7 @@ void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq)
 
        clear_bit(MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS, &rq->state);
 
-       if (unlikely(test_bit(MLX5E_RQ_STATE_FLUSH, &rq->state))) {
+       if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state))) {
                mlx5e_free_rx_mpwqe(rq, &rq->mpwqe.info[wq->head]);
                return;
        }
@@ -445,7 +445,7 @@ void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
 }
 
 #define RQ_CANNOT_POST(rq) \
-       (test_bit(MLX5E_RQ_STATE_FLUSH, &rq->state) || \
+       (!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state) || \
         test_bit(MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS, &rq->state))
 
 bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
@@ -924,7 +924,7 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
        struct mlx5e_sq *xdp_sq = &rq->channel->xdp_sq;
        int work_done = 0;
 
-       if (unlikely(test_bit(MLX5E_RQ_STATE_FLUSH, &rq->state)))
+       if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
                return 0;
 
        if (cq->decmprs_left)
index ce8c54d18906bedc57f0bdd8353e1f2156d47ce7..6bb21b31cfebfb94e69057c312c4f95c5b0f1540 100644 (file)
@@ -237,12 +237,15 @@ static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec
                        skb_flow_dissector_target(f->dissector,
                                                  FLOW_DISSECTOR_KEY_VLAN,
                                                  f->mask);
-               if (mask->vlan_id) {
+               if (mask->vlan_id || mask->vlan_priority) {
                        MLX5_SET(fte_match_set_lyr_2_4, headers_c, vlan_tag, 1);
                        MLX5_SET(fte_match_set_lyr_2_4, headers_v, vlan_tag, 1);
 
                        MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, mask->vlan_id);
                        MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, key->vlan_id);
+
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_prio, mask->vlan_priority);
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, key->vlan_priority);
                }
        }
 
index 70a717382357eecc74c766700a6fbad9d17e93dd..cfb68371c397e0b19b231ba2730d4d54179d0fd5 100644 (file)
@@ -409,7 +409,7 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
 
        sq = container_of(cq, struct mlx5e_sq, cq);
 
-       if (unlikely(test_bit(MLX5E_SQ_STATE_FLUSH, &sq->state)))
+       if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
                return false;
 
        npkts = 0;
index 5703f19a6a2454551d6ddc29d3644fabd52ea3e0..e5c12a732aa1212274943183ed83696ce2606639 100644 (file)
@@ -56,7 +56,7 @@ static void mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
        struct mlx5_cqe64 *cqe;
        u16 sqcc;
 
-       if (unlikely(test_bit(MLX5E_SQ_STATE_FLUSH, &sq->state)))
+       if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
                return;
 
        cqe = mlx5e_get_cqe(cq);
@@ -113,7 +113,7 @@ static inline bool mlx5e_poll_xdp_tx_cq(struct mlx5e_cq *cq)
 
        sq = container_of(cq, struct mlx5e_sq, cq);
 
-       if (unlikely(test_bit(MLX5E_SQ_STATE_FLUSH, &sq->state)))
+       if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
                return false;
 
        /* sq->cc must be updated only after mlx5_cqwq_update_db_record(),
index abbf2c369923d02534b1ebfa82e212bcefce0333..be1f7333ab7f6845acc01ae46fd9ba150f6ad6aa 100644 (file)
@@ -931,8 +931,8 @@ static void esw_vport_change_handler(struct work_struct *work)
        mutex_unlock(&esw->state_lock);
 }
 
-static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
-                                       struct mlx5_vport *vport)
+static int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
+                                      struct mlx5_vport *vport)
 {
        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
        struct mlx5_flow_group *vlan_grp = NULL;
@@ -949,9 +949,11 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
        int table_size = 2;
        int err = 0;
 
-       if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support) ||
-           !IS_ERR_OR_NULL(vport->egress.acl))
-               return;
+       if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
+               return -EOPNOTSUPP;
+
+       if (!IS_ERR_OR_NULL(vport->egress.acl))
+               return 0;
 
        esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n",
                  vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
@@ -959,12 +961,12 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS);
        if (!root_ns) {
                esw_warn(dev, "Failed to get E-Switch egress flow namespace\n");
-               return;
+               return -EIO;
        }
 
        flow_group_in = mlx5_vzalloc(inlen);
        if (!flow_group_in)
-               return;
+               return -ENOMEM;
 
        acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
        if (IS_ERR(acl)) {
@@ -1009,6 +1011,7 @@ out:
                mlx5_destroy_flow_group(vlan_grp);
        if (err && !IS_ERR_OR_NULL(acl))
                mlx5_destroy_flow_table(acl);
+       return err;
 }
 
 static void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw,
@@ -1041,8 +1044,8 @@ static void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw,
        vport->egress.acl = NULL;
 }
 
-static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
-                                        struct mlx5_vport *vport)
+static int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
+                                       struct mlx5_vport *vport)
 {
        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
        struct mlx5_core_dev *dev = esw->dev;
@@ -1063,9 +1066,11 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
        int table_size = 4;
        int err = 0;
 
-       if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support) ||
-           !IS_ERR_OR_NULL(vport->ingress.acl))
-               return;
+       if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
+               return -EOPNOTSUPP;
+
+       if (!IS_ERR_OR_NULL(vport->ingress.acl))
+               return 0;
 
        esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n",
                  vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
@@ -1073,12 +1078,12 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS);
        if (!root_ns) {
                esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n");
-               return;
+               return -EIO;
        }
 
        flow_group_in = mlx5_vzalloc(inlen);
        if (!flow_group_in)
-               return;
+               return -ENOMEM;
 
        acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
        if (IS_ERR(acl)) {
@@ -1167,6 +1172,7 @@ out:
        }
 
        kvfree(flow_group_in);
+       return err;
 }
 
 static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
@@ -1225,7 +1231,13 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
                return 0;
        }
 
-       esw_vport_enable_ingress_acl(esw, vport);
+       err = esw_vport_enable_ingress_acl(esw, vport);
+       if (err) {
+               mlx5_core_warn(esw->dev,
+                              "failed to enable ingress acl (%d) on vport[%d]\n",
+                              err, vport->vport);
+               return err;
+       }
 
        esw_debug(esw->dev,
                  "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
@@ -1299,7 +1311,13 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
                return 0;
        }
 
-       esw_vport_enable_egress_acl(esw, vport);
+       err = esw_vport_enable_egress_acl(esw, vport);
+       if (err) {
+               mlx5_core_warn(esw->dev,
+                              "failed to enable egress acl (%d) on vport[%d]\n",
+                              err, vport->vport);
+               return err;
+       }
 
        esw_debug(esw->dev,
                  "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
index c55ad8d00c05714710b36b568ed57ab1026bd8cb..d239f5d0ea3683d886a7e21dc9d7d6274e15a65e 100644 (file)
@@ -57,7 +57,8 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
        if (esw->mode != SRIOV_OFFLOADS)
                return ERR_PTR(-EOPNOTSUPP);
 
-       action = attr->action;
+       /* per flow vlan pop/push is emulated, don't set that into the firmware */
+       action = attr->action & ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH | MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
 
        if (action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
                dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
index 5da2cc878582438cef2caf89884d3065c23aae21..914e5466f729b65d706dc97d553fd774c94fc436 100644 (file)
@@ -436,6 +436,9 @@ static void del_flow_group(struct fs_node *node)
        fs_get_obj(ft, fg->node.parent);
        dev = get_dev(&ft->node);
 
+       if (ft->autogroup.active)
+               ft->autogroup.num_groups--;
+
        if (mlx5_cmd_destroy_flow_group(dev, ft, fg->id))
                mlx5_core_warn(dev, "flow steering can't destroy fg %d of ft %d\n",
                               fg->id, ft->id);
@@ -879,7 +882,7 @@ static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table *
        tree_init_node(&fg->node, !is_auto_fg, del_flow_group);
        tree_add_node(&fg->node, &ft->node);
        /* Add node to group list */
-       list_add(&fg->node.list, ft->node.children.prev);
+       list_add(&fg->node.list, prev_fg);
 
        return fg;
 }
@@ -893,7 +896,7 @@ struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft,
                return ERR_PTR(-EPERM);
 
        lock_ref_node(&ft->node);
-       fg = create_flow_group_common(ft, fg_in, &ft->node.children, false);
+       fg = create_flow_group_common(ft, fg_in, ft->node.children.prev, false);
        unlock_ref_node(&ft->node);
 
        return fg;
@@ -1012,7 +1015,7 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
                                                u32 *match_criteria)
 {
        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
-       struct list_head *prev = &ft->node.children;
+       struct list_head *prev = ft->node.children.prev;
        unsigned int candidate_index = 0;
        struct mlx5_flow_group *fg;
        void *match_criteria_addr;
@@ -1687,7 +1690,7 @@ static int init_root_ns(struct mlx5_flow_steering *steering)
 {
 
        steering->root_ns = create_root_ns(steering, FS_FT_NIC_RX);
-       if (IS_ERR_OR_NULL(steering->root_ns))
+       if (!steering->root_ns)
                goto cleanup;
 
        if (init_root_tree(steering, &root_fs, &steering->root_ns->ns.node))
index 3a9195b4169dc0b1cbbb60b31ac3d2a2ddadcecb..3b026c151cf24f370137b4655b417d6e024d6dec 100644 (file)
@@ -218,6 +218,7 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
                goto err_out;
 
        if (aging) {
+               counter->cache.lastuse = jiffies;
                counter->aging = true;
 
                spin_lock(&fc_stats->addlist_lock);
index 1a05fb965c8dd5051cc929f1fb4fbaaf4c4584e4..5bcf93422ee0b28337040138d026c2ab443642a9 100644 (file)
@@ -61,10 +61,15 @@ enum {
 enum {
        MLX5_NIC_IFC_FULL               = 0,
        MLX5_NIC_IFC_DISABLED           = 1,
-       MLX5_NIC_IFC_NO_DRAM_NIC        = 2
+       MLX5_NIC_IFC_NO_DRAM_NIC        = 2,
+       MLX5_NIC_IFC_INVALID            = 3
 };
 
-static u8 get_nic_interface(struct mlx5_core_dev *dev)
+enum {
+       MLX5_DROP_NEW_HEALTH_WORK,
+};
+
+static u8 get_nic_state(struct mlx5_core_dev *dev)
 {
        return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3;
 }
@@ -97,7 +102,7 @@ static int in_fatal(struct mlx5_core_dev *dev)
        struct mlx5_core_health *health = &dev->priv.health;
        struct health_buffer __iomem *h = health->health;
 
-       if (get_nic_interface(dev) == MLX5_NIC_IFC_DISABLED)
+       if (get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
                return 1;
 
        if (ioread32be(&h->fw_ver) == 0xffffffff)
@@ -127,7 +132,7 @@ unlock:
 
 static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
 {
-       u8 nic_interface = get_nic_interface(dev);
+       u8 nic_interface = get_nic_state(dev);
 
        switch (nic_interface) {
        case MLX5_NIC_IFC_FULL:
@@ -149,8 +154,34 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
        mlx5_disable_device(dev);
 }
 
+static void health_recover(struct work_struct *work)
+{
+       struct mlx5_core_health *health;
+       struct delayed_work *dwork;
+       struct mlx5_core_dev *dev;
+       struct mlx5_priv *priv;
+       u8 nic_state;
+
+       dwork = container_of(work, struct delayed_work, work);
+       health = container_of(dwork, struct mlx5_core_health, recover_work);
+       priv = container_of(health, struct mlx5_priv, health);
+       dev = container_of(priv, struct mlx5_core_dev, priv);
+
+       nic_state = get_nic_state(dev);
+       if (nic_state == MLX5_NIC_IFC_INVALID) {
+               dev_err(&dev->pdev->dev, "health recovery flow aborted since the nic state is invalid\n");
+               return;
+       }
+
+       dev_err(&dev->pdev->dev, "starting health recovery flow\n");
+       mlx5_recover_device(dev);
+}
+
+/* How much time to wait until health resetting the driver (in msecs) */
+#define MLX5_RECOVERY_DELAY_MSECS 60000
 static void health_care(struct work_struct *work)
 {
+       unsigned long recover_delay = msecs_to_jiffies(MLX5_RECOVERY_DELAY_MSECS);
        struct mlx5_core_health *health;
        struct mlx5_core_dev *dev;
        struct mlx5_priv *priv;
@@ -160,6 +191,14 @@ static void health_care(struct work_struct *work)
        dev = container_of(priv, struct mlx5_core_dev, priv);
        mlx5_core_warn(dev, "handling bad device here\n");
        mlx5_handle_bad_state(dev);
+
+       spin_lock(&health->wq_lock);
+       if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
+               schedule_delayed_work(&health->recover_work, recover_delay);
+       else
+               dev_err(&dev->pdev->dev,
+                       "new health works are not permitted at this stage\n");
+       spin_unlock(&health->wq_lock);
 }
 
 static const char *hsynd_str(u8 synd)
@@ -272,7 +311,13 @@ static void poll_health(unsigned long data)
        if (in_fatal(dev) && !health->sick) {
                health->sick = true;
                print_health_info(dev);
-               schedule_work(&health->work);
+               spin_lock(&health->wq_lock);
+               if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
+                       queue_work(health->wq, &health->work);
+               else
+                       dev_err(&dev->pdev->dev,
+                               "new health works are not permitted at this stage\n");
+               spin_unlock(&health->wq_lock);
        }
 }
 
@@ -281,6 +326,8 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev)
        struct mlx5_core_health *health = &dev->priv.health;
 
        init_timer(&health->timer);
+       health->sick = 0;
+       clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
        health->health = &dev->iseg->health;
        health->health_counter = &dev->iseg->health_counter;
 
@@ -297,11 +344,22 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev)
        del_timer_sync(&health->timer);
 }
 
+void mlx5_drain_health_wq(struct mlx5_core_dev *dev)
+{
+       struct mlx5_core_health *health = &dev->priv.health;
+
+       spin_lock(&health->wq_lock);
+       set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
+       spin_unlock(&health->wq_lock);
+       cancel_delayed_work_sync(&health->recover_work);
+       cancel_work_sync(&health->work);
+}
+
 void mlx5_health_cleanup(struct mlx5_core_dev *dev)
 {
        struct mlx5_core_health *health = &dev->priv.health;
 
-       flush_work(&health->work);
+       destroy_workqueue(health->wq);
 }
 
 int mlx5_health_init(struct mlx5_core_dev *dev)
@@ -316,9 +374,13 @@ int mlx5_health_init(struct mlx5_core_dev *dev)
 
        strcpy(name, "mlx5_health");
        strcat(name, dev_name(&dev->pdev->dev));
+       health->wq = create_singlethread_workqueue(name);
        kfree(name);
-
+       if (!health->wq)
+               return -ENOMEM;
+       spin_lock_init(&health->wq_lock);
        INIT_WORK(&health->work, health_care);
+       INIT_DELAYED_WORK(&health->recover_work, health_recover);
 
        return 0;
 }
index d9c3c70b29e4799f87a0daed286c272be6180d01..ada24e103b02ac927362b0aba5050c251a0e644b 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/mlx5/srq.h>
 #include <linux/debugfs.h>
 #include <linux/kmod.h>
-#include <linux/delay.h>
 #include <linux/mlx5/mlx5_ifc.h>
 #ifdef CONFIG_RFS_ACCEL
 #include <linux/cpu_rmap.h>
@@ -63,13 +62,13 @@ MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(DRIVER_VERSION);
 
-int mlx5_core_debug_mask;
-module_param_named(debug_mask, mlx5_core_debug_mask, int, 0644);
+unsigned int mlx5_core_debug_mask;
+module_param_named(debug_mask, mlx5_core_debug_mask, uint, 0644);
 MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0");
 
 #define MLX5_DEFAULT_PROF      2
-static int prof_sel = MLX5_DEFAULT_PROF;
-module_param_named(prof_sel, prof_sel, int, 0444);
+static unsigned int prof_sel = MLX5_DEFAULT_PROF;
+module_param_named(prof_sel, prof_sel, uint, 0444);
 MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2");
 
 enum {
@@ -733,13 +732,15 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev)
                u8 status;
 
                mlx5_cmd_mbox_status(query_out, &status, &syndrome);
-               if (status == MLX5_CMD_STAT_BAD_OP_ERR) {
-                       pr_debug("Only ISSI 0 is supported\n");
-                       return 0;
+               if (!status || syndrome == MLX5_DRIVER_SYND) {
+                       mlx5_core_err(dev, "Failed to query ISSI err(%d) status(%d) synd(%d)\n",
+                                     err, status, syndrome);
+                       return err;
                }
 
-               pr_err("failed to query ISSI err(%d)\n", err);
-               return err;
+               mlx5_core_warn(dev, "Query ISSI is not supported by FW, ISSI is 0\n");
+               dev->issi = 0;
+               return 0;
        }
 
        sup_issi = MLX5_GET(query_issi_out, query_out, supported_issi_dw0);
@@ -753,7 +754,8 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev)
                err = mlx5_cmd_exec(dev, set_in, sizeof(set_in),
                                    set_out, sizeof(set_out));
                if (err) {
-                       pr_err("failed to set ISSI=1 err(%d)\n", err);
+                       mlx5_core_err(dev, "Failed to set ISSI to 1 err(%d)\n",
+                                     err);
                        return err;
                }
 
@@ -844,12 +846,6 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
        struct pci_dev *pdev = dev->pdev;
        int err;
 
-       err = mlx5_query_hca_caps(dev);
-       if (err) {
-               dev_err(&pdev->dev, "query hca failed\n");
-               goto out;
-       }
-
        err = mlx5_query_board_id(dev);
        if (err) {
                dev_err(&pdev->dev, "query board id failed\n");
@@ -1023,6 +1019,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 
        mlx5_start_health_poll(dev);
 
+       err = mlx5_query_hca_caps(dev);
+       if (err) {
+               dev_err(&pdev->dev, "query hca failed\n");
+               goto err_stop_poll;
+       }
+
        if (boot && mlx5_init_once(dev, priv)) {
                dev_err(&pdev->dev, "sw objs init failed\n");
                goto err_stop_poll;
@@ -1226,15 +1228,9 @@ static int init_one(struct pci_dev *pdev,
 
        pci_set_drvdata(pdev, dev);
 
-       if (prof_sel < 0 || prof_sel >= ARRAY_SIZE(profile)) {
-               mlx5_core_warn(dev,
-                              "selected profile out of range, selecting default (%d)\n",
-                              MLX5_DEFAULT_PROF);
-               prof_sel = MLX5_DEFAULT_PROF;
-       }
-       dev->profile = &profile[prof_sel];
        dev->pdev = pdev;
        dev->event = mlx5_core_event;
+       dev->profile = &profile[prof_sel];
 
        INIT_LIST_HEAD(&priv->ctx_list);
        spin_lock_init(&priv->ctx_lock);
@@ -1313,10 +1309,16 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
        struct mlx5_priv *priv = &dev->priv;
 
        dev_info(&pdev->dev, "%s was called\n", __func__);
+
        mlx5_enter_error_state(dev);
        mlx5_unload_one(dev, priv, false);
-       pci_save_state(pdev);
-       mlx5_pci_disable_device(dev);
+       /* In case of kernel call save the pci state and drain health wq */
+       if (state) {
+               pci_save_state(pdev);
+               mlx5_drain_health_wq(dev);
+               mlx5_pci_disable_device(dev);
+       }
+
        return state == pci_channel_io_perm_failure ?
                PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
 }
@@ -1373,11 +1375,6 @@ static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev)
        return PCI_ERS_RESULT_RECOVERED;
 }
 
-void mlx5_disable_device(struct mlx5_core_dev *dev)
-{
-       mlx5_pci_err_detected(dev->pdev, 0);
-}
-
 static void mlx5_pci_resume(struct pci_dev *pdev)
 {
        struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
@@ -1427,6 +1424,18 @@ static const struct pci_device_id mlx5_core_pci_table[] = {
 
 MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table);
 
+void mlx5_disable_device(struct mlx5_core_dev *dev)
+{
+       mlx5_pci_err_detected(dev->pdev, 0);
+}
+
+void mlx5_recover_device(struct mlx5_core_dev *dev)
+{
+       mlx5_pci_disable_device(dev);
+       if (mlx5_pci_slot_reset(dev->pdev) == PCI_ERS_RESULT_RECOVERED)
+               mlx5_pci_resume(dev->pdev);
+}
+
 static struct pci_driver mlx5_core_driver = {
        .name           = DRIVER_NAME,
        .id_table       = mlx5_core_pci_table,
@@ -1437,10 +1446,22 @@ static struct pci_driver mlx5_core_driver = {
        .sriov_configure   = mlx5_core_sriov_configure,
 };
 
+static void mlx5_core_verify_params(void)
+{
+       if (prof_sel >= ARRAY_SIZE(profile)) {
+               pr_warn("mlx5_core: WARNING: Invalid module parameter prof_sel %d, valid range 0-%zu, changing back to default(%d)\n",
+                       prof_sel,
+                       ARRAY_SIZE(profile) - 1,
+                       MLX5_DEFAULT_PROF);
+               prof_sel = MLX5_DEFAULT_PROF;
+       }
+}
+
 static int __init init(void)
 {
        int err;
 
+       mlx5_core_verify_params();
        mlx5_register_debugfs();
 
        err = pci_register_driver(&mlx5_core_driver);
index 3d0cfb9f18f99154e6f904625a41ff457c4e2508..63b9a0dba88555510300d68e26918465cadbf8f6 100644 (file)
 
 #define MLX5_TOTAL_VPORTS(mdev) (1 + pci_sriov_get_totalvfs(mdev->pdev))
 
-extern int mlx5_core_debug_mask;
+extern uint mlx5_core_debug_mask;
 
 #define mlx5_core_dbg(__dev, format, ...)                              \
-       dev_dbg(&(__dev)->pdev->dev, "%s:%s:%d:(pid %d): " format,      \
-                (__dev)->priv.name, __func__, __LINE__, current->pid,  \
+       dev_dbg(&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,         \
+                __func__, __LINE__, current->pid,                      \
                 ##__VA_ARGS__)
 
 #define mlx5_core_dbg_mask(__dev, mask, format, ...)                   \
@@ -63,8 +63,8 @@ do {                                                                  \
               ##__VA_ARGS__)
 
 #define mlx5_core_warn(__dev, format, ...)                             \
-       dev_warn(&(__dev)->pdev->dev, "%s:%s:%d:(pid %d): " format,     \
-               (__dev)->priv.name, __func__, __LINE__, current->pid,   \
+       dev_warn(&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,        \
+                __func__, __LINE__, current->pid,                      \
                ##__VA_ARGS__)
 
 #define mlx5_core_info(__dev, format, ...)                             \
@@ -75,6 +75,11 @@ enum {
        MLX5_CMD_TIME, /* print command execution time */
 };
 
+enum {
+       MLX5_DRIVER_STATUS_ABORTED = 0xfe,
+       MLX5_DRIVER_SYND = 0xbadd00de,
+};
+
 int mlx5_query_hca_caps(struct mlx5_core_dev *dev);
 int mlx5_query_board_id(struct mlx5_core_dev *dev);
 int mlx5_cmd_init_hca(struct mlx5_core_dev *dev);
@@ -83,6 +88,7 @@ void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
                     unsigned long param);
 void mlx5_enter_error_state(struct mlx5_core_dev *dev);
 void mlx5_disable_device(struct mlx5_core_dev *dev);
+void mlx5_recover_device(struct mlx5_core_dev *dev);
 int mlx5_sriov_init(struct mlx5_core_dev *dev);
 void mlx5_sriov_cleanup(struct mlx5_core_dev *dev);
 int mlx5_sriov_attach(struct mlx5_core_dev *dev);
index cc4fd61914d30b567d962f24f15bfea3bb1da92c..a57d5a81eb05dbbb30054519ceb543ad4879c6ef 100644 (file)
@@ -209,6 +209,7 @@ static void free_4k(struct mlx5_core_dev *dev, u64 addr)
 static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id)
 {
        struct page *page;
+       u64 zero_addr = 1;
        u64 addr;
        int err;
        int nid = dev_to_node(&dev->pdev->dev);
@@ -218,26 +219,35 @@ static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id)
                mlx5_core_warn(dev, "failed to allocate page\n");
                return -ENOMEM;
        }
+map:
        addr = dma_map_page(&dev->pdev->dev, page, 0,
                            PAGE_SIZE, DMA_BIDIRECTIONAL);
        if (dma_mapping_error(&dev->pdev->dev, addr)) {
                mlx5_core_warn(dev, "failed dma mapping page\n");
                err = -ENOMEM;
-               goto out_alloc;
+               goto err_mapping;
        }
+
+       /* Firmware doesn't support page with physical address 0 */
+       if (addr == 0) {
+               zero_addr = addr;
+               goto map;
+       }
+
        err = insert_page(dev, addr, page, func_id);
        if (err) {
                mlx5_core_err(dev, "failed to track allocated page\n");
-               goto out_mapping;
+               dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE,
+                              DMA_BIDIRECTIONAL);
        }
 
-       return 0;
-
-out_mapping:
-       dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
+err_mapping:
+       if (err)
+               __free_page(page);
 
-out_alloc:
-       __free_page(page);
+       if (zero_addr == 0)
+               dma_unmap_page(&dev->pdev->dev, zero_addr, PAGE_SIZE,
+                              DMA_BIDIRECTIONAL);
 
        return err;
 }
index e742bd4e8894a4493d60251a44dbd1209b310601..912f71f84209d3e22a386cf36498bbfccb541047 100644 (file)
@@ -1838,11 +1838,17 @@ static const struct mlxsw_bus mlxsw_pci_bus = {
        .cmd_exec               = mlxsw_pci_cmd_exec,
 };
 
-static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci)
+static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
+                             const struct pci_device_id *id)
 {
        unsigned long end;
 
        mlxsw_pci_write32(mlxsw_pci, SW_RESET, MLXSW_PCI_SW_RESET_RST_BIT);
+       if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) {
+               msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
+               return 0;
+       }
+
        wmb(); /* reset needs to be written before we read control register */
        end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
        do {
@@ -1909,7 +1915,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        mlxsw_pci->pdev = pdev;
        pci_set_drvdata(pdev, mlxsw_pci);
 
-       err = mlxsw_pci_sw_reset(mlxsw_pci);
+       err = mlxsw_pci_sw_reset(mlxsw_pci, id);
        if (err) {
                dev_err(&pdev->dev, "Software reset failed\n");
                goto err_sw_reset;
index 1ec0a4ce3c46edddc4fc0d63e67706d6459e10f3..dda5761e91bcbe27738cafd79d73e5a25f1f8b66 100644 (file)
@@ -231,7 +231,7 @@ mlxsw_sp_span_entry_create(struct mlxsw_sp_port *port)
 
        span_entry->used = true;
        span_entry->id = index;
-       span_entry->ref_count = 0;
+       span_entry->ref_count = 1;
        span_entry->local_port = local_port;
        return span_entry;
 }
@@ -270,6 +270,7 @@ static struct mlxsw_sp_span_entry
 
        span_entry = mlxsw_sp_span_entry_find(port);
        if (span_entry) {
+               /* Already exists, just take a reference */
                span_entry->ref_count++;
                return span_entry;
        }
@@ -280,6 +281,7 @@ static struct mlxsw_sp_span_entry
 static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
                                   struct mlxsw_sp_span_entry *span_entry)
 {
+       WARN_ON(!span_entry->ref_count);
        if (--span_entry->ref_count == 0)
                mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry);
        return 0;
index 9b22863a924b53d44b59ea5f07b61a500fc889cf..97bbc1d21df89bcfd3bd0b3bed046d16663ac6f5 100644 (file)
@@ -115,7 +115,7 @@ struct mlxsw_sp_rif {
 struct mlxsw_sp_mid {
        struct list_head list;
        unsigned char addr[ETH_ALEN];
-       u16 vid;
+       u16 fid;
        u16 mid;
        unsigned int ref_count;
 };
index 78fc557d6dd79313e0a6a99790a5261bd79b30f3..e83072da6272c6583ed72cc6546bbed2676580ce 100644 (file)
@@ -320,6 +320,8 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
                                                lpm_tree);
        if (err)
                goto err_left_struct_set;
+       memcpy(&lpm_tree->prefix_usage, prefix_usage,
+              sizeof(lpm_tree->prefix_usage));
        return lpm_tree;
 
 err_left_struct_set:
@@ -343,7 +345,8 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
 
        for (i = 0; i < MLXSW_SP_LPM_TREE_COUNT; i++) {
                lpm_tree = &mlxsw_sp->router.lpm_trees[i];
-               if (lpm_tree->proto == proto &&
+               if (lpm_tree->ref_count != 0 &&
+                   lpm_tree->proto == proto &&
                    mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
                                             prefix_usage))
                        goto inc_ref_count;
@@ -591,21 +594,22 @@ static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
        return 0;
 }
 
+static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp);
+
 static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
 {
+       mlxsw_sp_router_fib_flush(mlxsw_sp);
        kfree(mlxsw_sp->router.vrs);
 }
 
 struct mlxsw_sp_neigh_key {
-       unsigned char addr[sizeof(struct in6_addr)];
-       struct net_device *dev;
+       struct neighbour *n;
 };
 
 struct mlxsw_sp_neigh_entry {
        struct rhash_head ht_node;
        struct mlxsw_sp_neigh_key key;
        u16 rif;
-       struct neighbour *n;
        bool offloaded;
        struct delayed_work dw;
        struct mlxsw_sp_port *mlxsw_sp_port;
@@ -643,19 +647,15 @@ mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
 static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work);
 
 static struct mlxsw_sp_neigh_entry *
-mlxsw_sp_neigh_entry_create(const void *addr, size_t addr_len,
-                           struct net_device *dev, u16 rif,
-                           struct neighbour *n)
+mlxsw_sp_neigh_entry_create(struct neighbour *n, u16 rif)
 {
        struct mlxsw_sp_neigh_entry *neigh_entry;
 
        neigh_entry = kzalloc(sizeof(*neigh_entry), GFP_ATOMIC);
        if (!neigh_entry)
                return NULL;
-       memcpy(neigh_entry->key.addr, addr, addr_len);
-       neigh_entry->key.dev = dev;
+       neigh_entry->key.n = n;
        neigh_entry->rif = rif;
-       neigh_entry->n = n;
        INIT_DELAYED_WORK(&neigh_entry->dw, mlxsw_sp_router_neigh_update_hw);
        INIT_LIST_HEAD(&neigh_entry->nexthop_list);
        return neigh_entry;
@@ -668,13 +668,11 @@ mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp_neigh_entry *neigh_entry)
 }
 
 static struct mlxsw_sp_neigh_entry *
-mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, const void *addr,
-                           size_t addr_len, struct net_device *dev)
+mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
 {
-       struct mlxsw_sp_neigh_key key = {{ 0 } };
+       struct mlxsw_sp_neigh_key key;
 
-       memcpy(key.addr, addr, addr_len);
-       key.dev = dev;
+       key.n = n;
        return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht,
                                      &key, mlxsw_sp_neigh_ht_params);
 }
@@ -686,26 +684,20 @@ int mlxsw_sp_router_neigh_construct(struct net_device *dev,
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_neigh_entry *neigh_entry;
        struct mlxsw_sp_rif *r;
-       u32 dip;
        int err;
 
        if (n->tbl != &arp_tbl)
                return 0;
 
-       dip = ntohl(*((__be32 *) n->primary_key));
-       neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip),
-                                                 n->dev);
-       if (neigh_entry) {
-               WARN_ON(neigh_entry->n != n);
+       neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
+       if (neigh_entry)
                return 0;
-       }
 
        r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev);
        if (WARN_ON(!r))
                return -EINVAL;
 
-       neigh_entry = mlxsw_sp_neigh_entry_create(&dip, sizeof(dip), n->dev,
-                                                 r->rif, n);
+       neigh_entry = mlxsw_sp_neigh_entry_create(n, r->rif);
        if (!neigh_entry)
                return -ENOMEM;
        err = mlxsw_sp_neigh_entry_insert(mlxsw_sp, neigh_entry);
@@ -724,14 +716,11 @@ void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_neigh_entry *neigh_entry;
-       u32 dip;
 
        if (n->tbl != &arp_tbl)
                return;
 
-       dip = ntohl(*((__be32 *) n->primary_key));
-       neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &dip, sizeof(dip),
-                                                 n->dev);
+       neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
        if (!neigh_entry)
                return;
        mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
@@ -814,6 +803,26 @@ static void mlxsw_sp_router_neigh_rec_process(struct mlxsw_sp *mlxsw_sp,
        }
 }
 
+static bool mlxsw_sp_router_rauhtd_is_full(char *rauhtd_pl)
+{
+       u8 num_rec, last_rec_index, num_entries;
+
+       num_rec = mlxsw_reg_rauhtd_num_rec_get(rauhtd_pl);
+       last_rec_index = num_rec - 1;
+
+       if (num_rec < MLXSW_REG_RAUHTD_REC_MAX_NUM)
+               return false;
+       if (mlxsw_reg_rauhtd_rec_type_get(rauhtd_pl, last_rec_index) ==
+           MLXSW_REG_RAUHTD_TYPE_IPV6)
+               return true;
+
+       num_entries = mlxsw_reg_rauhtd_ipv4_rec_num_entries_get(rauhtd_pl,
+                                                               last_rec_index);
+       if (++num_entries == MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC)
+               return true;
+       return false;
+}
+
 static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
 {
        char *rauhtd_pl;
@@ -840,7 +849,7 @@ static int mlxsw_sp_router_neighs_update_rauhtd(struct mlxsw_sp *mlxsw_sp)
                for (i = 0; i < num_rec; i++)
                        mlxsw_sp_router_neigh_rec_process(mlxsw_sp, rauhtd_pl,
                                                          i);
-       } while (num_rec);
+       } while (mlxsw_sp_router_rauhtd_is_full(rauhtd_pl));
        rtnl_unlock();
 
        kfree(rauhtd_pl);
@@ -859,7 +868,7 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
                 * is active regardless of the traffic.
                 */
                if (!list_empty(&neigh_entry->nexthop_list))
-                       neigh_event_send(neigh_entry->n, NULL);
+                       neigh_event_send(neigh_entry->key.n, NULL);
        }
        rtnl_unlock();
 }
@@ -905,9 +914,9 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
        rtnl_lock();
        list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
                            nexthop_neighs_list_node) {
-               if (!(neigh_entry->n->nud_state & NUD_VALID) &&
+               if (!(neigh_entry->key.n->nud_state & NUD_VALID) &&
                    !list_empty(&neigh_entry->nexthop_list))
-                       neigh_event_send(neigh_entry->n, NULL);
+                       neigh_event_send(neigh_entry->key.n, NULL);
        }
        rtnl_unlock();
 
@@ -924,7 +933,7 @@ static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work)
 {
        struct mlxsw_sp_neigh_entry *neigh_entry =
                container_of(work, struct mlxsw_sp_neigh_entry, dw.work);
-       struct neighbour *n = neigh_entry->n;
+       struct neighbour *n = neigh_entry->key.n;
        struct mlxsw_sp_port *mlxsw_sp_port = neigh_entry->mlxsw_sp_port;
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        char rauht_pl[MLXSW_REG_RAUHT_LEN];
@@ -1027,11 +1036,8 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
 
                mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
                dip = ntohl(*((__be32 *) n->primary_key));
-               neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp,
-                                                         &dip,
-                                                         sizeof(__be32),
-                                                         dev);
-               if (WARN_ON(!neigh_entry) || WARN_ON(neigh_entry->n != n)) {
+               neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
+               if (WARN_ON(!neigh_entry)) {
                        mlxsw_sp_port_dev_put(mlxsw_sp_port);
                        return NOTIFY_DONE;
                }
@@ -1340,33 +1346,26 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp,
                                 struct fib_nh *fib_nh)
 {
        struct mlxsw_sp_neigh_entry *neigh_entry;
-       u32 gwip = ntohl(fib_nh->nh_gw);
        struct net_device *dev = fib_nh->nh_dev;
        struct neighbour *n;
        u8 nud_state;
 
-       neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &gwip,
-                                                 sizeof(gwip), dev);
-       if (!neigh_entry) {
-               __be32 gwipn = htonl(gwip);
-
-               n = neigh_create(&arp_tbl, &gwipn, dev);
+       /* Take a reference of neigh here ensuring that neigh would
+        * not be detructed before the nexthop entry is finished.
+        * The reference is taken either in neigh_lookup() or
+        * in neith_create() in case n is not found.
+        */
+       n = neigh_lookup(&arp_tbl, &fib_nh->nh_gw, dev);
+       if (!n) {
+               n = neigh_create(&arp_tbl, &fib_nh->nh_gw, dev);
                if (IS_ERR(n))
                        return PTR_ERR(n);
                neigh_event_send(n, NULL);
-               neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, &gwip,
-                                                         sizeof(gwip), dev);
-               if (!neigh_entry) {
-                       neigh_release(n);
-                       return -EINVAL;
-               }
-       } else {
-               /* Take a reference of neigh here ensuring that neigh would
-                * not be detructed before the nexthop entry is finished.
-                * The second branch takes the reference in neith_create()
-                */
-               n = neigh_entry->n;
-               neigh_clone(n);
+       }
+       neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
+       if (!neigh_entry) {
+               neigh_release(n);
+               return -EINVAL;
        }
 
        /* If that is the first nexthop connected to that neigh, add to
@@ -1400,7 +1399,7 @@ static void mlxsw_sp_nexthop_fini(struct mlxsw_sp *mlxsw_sp,
        if (list_empty(&nh->neigh_entry->nexthop_list))
                list_del(&nh->neigh_entry->nexthop_neighs_list_node);
 
-       neigh_release(neigh_entry->n);
+       neigh_release(neigh_entry->key.n);
 }
 
 static struct mlxsw_sp_nexthop_group *
@@ -1460,11 +1459,11 @@ static bool mlxsw_sp_nexthop_match(struct mlxsw_sp_nexthop *nh,
 
        for (i = 0; i < fi->fib_nhs; i++) {
                struct fib_nh *fib_nh = &fi->fib_nh[i];
-               u32 gwip = ntohl(fib_nh->nh_gw);
+               struct neighbour *n = nh->neigh_entry->key.n;
 
-               if (memcmp(nh->neigh_entry->key.addr,
-                          &gwip, sizeof(u32)) == 0 &&
-                   nh->neigh_entry->key.dev == fib_nh->nh_dev)
+               if (memcmp(n->primary_key, &fib_nh->nh_gw,
+                          sizeof(fib_nh->nh_gw)) == 0 &&
+                   n->dev == fib_nh->nh_dev)
                        return true;
        }
        return false;
@@ -1820,19 +1819,17 @@ err_fib_entry_insert:
        return err;
 }
 
-static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
-                                   struct fib_entry_notifier_info *fen_info)
+static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
+                                    struct fib_entry_notifier_info *fen_info)
 {
        struct mlxsw_sp_fib_entry *fib_entry;
 
        if (mlxsw_sp->router.aborted)
-               return 0;
+               return;
 
        fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fen_info);
-       if (!fib_entry) {
-               dev_warn(mlxsw_sp->bus_info->dev, "Failed to find FIB4 entry being removed.\n");
-               return -ENOENT;
-       }
+       if (!fib_entry)
+               return;
 
        if (fib_entry->ref_count == 1) {
                mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
@@ -1840,7 +1837,6 @@ static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
        }
 
        mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
-       return 0;
 }
 
 static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
@@ -1862,7 +1858,8 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
        if (err)
                return err;
 
-       mlxsw_reg_raltb_pack(raltb_pl, 0, MLXSW_REG_RALXX_PROTOCOL_IPV4, 0);
+       mlxsw_reg_raltb_pack(raltb_pl, 0, MLXSW_REG_RALXX_PROTOCOL_IPV4,
+                            MLXSW_SP_LPM_TREE_MIN);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
        if (err)
                return err;
@@ -1873,18 +1870,18 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
-static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp)
+static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
 {
        struct mlxsw_resources *resources;
        struct mlxsw_sp_fib_entry *fib_entry;
        struct mlxsw_sp_fib_entry *tmp;
        struct mlxsw_sp_vr *vr;
        int i;
-       int err;
 
        resources = mlxsw_core_resources_get(mlxsw_sp->core);
        for (i = 0; i < resources->max_virtual_routers; i++) {
                vr = &mlxsw_sp->router.vrs[i];
+
                if (!vr->used)
                        continue;
 
@@ -1900,6 +1897,13 @@ static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp)
                                break;
                }
        }
+}
+
+static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp)
+{
+       int err;
+
+       mlxsw_sp_router_fib_flush(mlxsw_sp);
        mlxsw_sp->router.aborted = true;
        err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
        if (err)
@@ -1957,6 +1961,9 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
        struct fib_entry_notifier_info *fen_info = ptr;
        int err;
 
+       if (!net_eq(fen_info->info.net, &init_net))
+               return NOTIFY_DONE;
+
        switch (event) {
        case FIB_EVENT_ENTRY_ADD:
                err = mlxsw_sp_router_fib4_add(mlxsw_sp, fen_info);
index 5e00c79e8133b016684972d0d269c904ec2e2c54..1e2c8eca3af1e6a7463a5f7bbb74edbca3db4540 100644 (file)
@@ -929,12 +929,12 @@ static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mid,
 
 static struct mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp *mlxsw_sp,
                                              const unsigned char *addr,
-                                             u16 vid)
+                                             u16 fid)
 {
        struct mlxsw_sp_mid *mid;
 
        list_for_each_entry(mid, &mlxsw_sp->br_mids.list, list) {
-               if (ether_addr_equal(mid->addr, addr) && mid->vid == vid)
+               if (ether_addr_equal(mid->addr, addr) && mid->fid == fid)
                        return mid;
        }
        return NULL;
@@ -942,7 +942,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp *mlxsw_sp,
 
 static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
                                                const unsigned char *addr,
-                                               u16 vid)
+                                               u16 fid)
 {
        struct mlxsw_sp_mid *mid;
        u16 mid_idx;
@@ -958,7 +958,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
 
        set_bit(mid_idx, mlxsw_sp->br_mids.mapped);
        ether_addr_copy(mid->addr, addr);
-       mid->vid = vid;
+       mid->fid = fid;
        mid->mid = mid_idx;
        mid->ref_count = 0;
        list_add_tail(&mid->list, &mlxsw_sp->br_mids.list);
@@ -991,9 +991,9 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
        if (switchdev_trans_ph_prepare(trans))
                return 0;
 
-       mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, mdb->vid);
+       mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid);
        if (!mid) {
-               mid = __mlxsw_sp_mc_alloc(mlxsw_sp, mdb->addr, mdb->vid);
+               mid = __mlxsw_sp_mc_alloc(mlxsw_sp, mdb->addr, fid);
                if (!mid) {
                        netdev_err(dev, "Unable to allocate MC group\n");
                        return -ENOMEM;
@@ -1137,7 +1137,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
        u16 mid_idx;
        int err = 0;
 
-       mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, mdb->vid);
+       mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid);
        if (!mid) {
                netdev_err(dev, "Unable to remove port from MC DB\n");
                return -EINVAL;
index c0c23e2f3275ae4b64f7f3444e4321811b4c6fa8..92bda8703f8752756c472aac916a19c8e5f38a65 100644 (file)
@@ -1088,6 +1088,7 @@ err_port_stp_state_set:
 err_port_admin_status_set:
 err_port_mtu_set:
 err_port_speed_set:
+       mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
 err_port_swid_set:
 err_port_system_port_mapping_set:
 port_not_usable:
index 1e8339a67f6e1d049fc60fe340715fd663742009..32f2a45f4ab24aa9ffe1cacb7abcf7f64fa4b3ac 100644 (file)
@@ -107,4 +107,7 @@ config QEDE
        ---help---
          This enables the support for ...
 
+config QED_RDMA
+       bool
+
 endif # NET_VENDOR_QLOGIC
index cda0af7fbc20dae2bdaeef710faa3e42486f9c64..967acf322c09a704d2993e2bf9d922bfd8eef906 100644 (file)
@@ -5,4 +5,4 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
         qed_selftest.o qed_dcbx.o qed_debug.o
 qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
 qed-$(CONFIG_QED_LL2) += qed_ll2.o
-qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o
+qed-$(CONFIG_QED_RDMA) += qed_roce.o
index 82370a1a59ad9e3a4e316c223d3c83d2641a80c5..0c42c240b5cfdff66dc8ef021b2401812a0fec17 100644 (file)
 #define TM_ALIGN        BIT(TM_SHIFT)
 #define TM_ELEM_SIZE    4
 
-/* ILT constants */
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
 /* For RoCE we configure to 64K to cover for RoCE max tasks 256K purpose. */
-#define ILT_DEFAULT_HW_P_SIZE          4
-#else
-#define ILT_DEFAULT_HW_P_SIZE          3
-#endif
+#define ILT_DEFAULT_HW_P_SIZE  (IS_ENABLED(CONFIG_QED_RDMA) ? 4 : 3)
 
 #define ILT_PAGE_IN_BYTES(hw_p_size)   (1U << ((hw_p_size) + 12))
 #define ILT_CFG_REG(cli, reg)  PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET
@@ -349,14 +344,14 @@ static struct qed_tid_seg *qed_cxt_tid_seg_info(struct qed_hwfn *p_hwfn,
        return NULL;
 }
 
-void qed_cxt_set_srq_count(struct qed_hwfn *p_hwfn, u32 num_srqs)
+static void qed_cxt_set_srq_count(struct qed_hwfn *p_hwfn, u32 num_srqs)
 {
        struct qed_cxt_mngr *p_mgr = p_hwfn->p_cxt_mngr;
 
        p_mgr->srq_count = num_srqs;
 }
 
-u32 qed_cxt_get_srq_count(struct qed_hwfn *p_hwfn)
+static u32 qed_cxt_get_srq_count(struct qed_hwfn *p_hwfn)
 {
        struct qed_cxt_mngr *p_mgr = p_hwfn->p_cxt_mngr;
 
@@ -1804,8 +1799,8 @@ int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, struct qed_cxt_info *p_info)
        return 0;
 }
 
-void qed_rdma_set_pf_params(struct qed_hwfn *p_hwfn,
-                           struct qed_rdma_pf_params *p_params)
+static void qed_rdma_set_pf_params(struct qed_hwfn *p_hwfn,
+                                  struct qed_rdma_pf_params *p_params)
 {
        u32 num_cons, num_tasks, num_qps, num_mrs, num_srqs;
        enum protocol_type proto;
index 130da1c0490be6ff482e563c088aee66d23db131..a4789a93b69267cd749b92962355083cd007afa4 100644 (file)
@@ -1190,6 +1190,7 @@ int qed_dcbx_get_config_params(struct qed_hwfn *p_hwfn,
        if (!dcbx_info)
                return -ENOMEM;
 
+       memset(dcbx_info, 0, sizeof(*dcbx_info));
        rc = qed_dcbx_query_params(p_hwfn, dcbx_info, QED_DCBX_OPERATIONAL_MIB);
        if (rc) {
                kfree(dcbx_info);
@@ -1225,6 +1226,7 @@ static struct qed_dcbx_get *qed_dcbnl_get_dcbx(struct qed_hwfn *hwfn,
        if (!dcbx_info)
                return NULL;
 
+       memset(dcbx_info, 0, sizeof(*dcbx_info));
        if (qed_dcbx_query_params(hwfn, dcbx_info, type)) {
                kfree(dcbx_info);
                return NULL;
index 88e7d5bef9098462fa06ca1f0851a396ac8386d8..68f19ca57f965b13d6fbf32c85e86d65e500b881 100644 (file)
@@ -405,7 +405,7 @@ struct phy_defs {
 /***************************** Constant Arrays *******************************/
 
 /* Debug arrays */
-static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {0} };
+static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} };
 
 /* Chip constant definitions array */
 static struct chip_defs s_chip_defs[MAX_CHIP_IDS] = {
@@ -4028,10 +4028,10 @@ static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn,
 }
 
 /* Dump MCP Trace */
-enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn,
-                                  struct qed_ptt *p_ptt,
-                                  u32 *dump_buf,
-                                  bool dump, u32 *num_dumped_dwords)
+static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn,
+                                         struct qed_ptt *p_ptt,
+                                         u32 *dump_buf,
+                                         bool dump, u32 *num_dumped_dwords)
 {
        u32 trace_data_grc_addr, trace_data_size_bytes, trace_data_size_dwords;
        u32 trace_meta_size_dwords, running_bundle_id, offset = 0;
@@ -4130,10 +4130,10 @@ enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn,
 }
 
 /* Dump GRC FIFO */
-enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn,
-                                 struct qed_ptt *p_ptt,
-                                 u32 *dump_buf,
-                                 bool dump, u32 *num_dumped_dwords)
+static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn,
+                                        struct qed_ptt *p_ptt,
+                                        u32 *dump_buf,
+                                        bool dump, u32 *num_dumped_dwords)
 {
        u32 offset = 0, dwords_read, size_param_offset;
        bool fifo_has_data;
@@ -4192,10 +4192,10 @@ enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn,
 }
 
 /* Dump IGU FIFO */
-enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn,
-                                 struct qed_ptt *p_ptt,
-                                 u32 *dump_buf,
-                                 bool dump, u32 *num_dumped_dwords)
+static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn,
+                                        struct qed_ptt *p_ptt,
+                                        u32 *dump_buf,
+                                        bool dump, u32 *num_dumped_dwords)
 {
        u32 offset = 0, dwords_read, size_param_offset;
        bool fifo_has_data;
@@ -4255,10 +4255,11 @@ enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn,
 }
 
 /* Protection Override dump */
-enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn,
-                                            struct qed_ptt *p_ptt,
-                                            u32 *dump_buf,
-                                            bool dump, u32 *num_dumped_dwords)
+static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn,
+                                                   struct qed_ptt *p_ptt,
+                                                   u32 *dump_buf,
+                                                   bool dump,
+                                                   u32 *num_dumped_dwords)
 {
        u32 offset = 0, size_param_offset, override_window_dwords;
 
@@ -6339,10 +6340,11 @@ enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn,
 }
 
 /* Wrapper for unifying the idle_chk and mcp_trace api */
-enum dbg_status qed_print_idle_chk_results_wrapper(struct qed_hwfn *p_hwfn,
-                                                  u32 *dump_buf,
-                                                  u32 num_dumped_dwords,
-                                                  char *results_buf)
+static enum dbg_status
+qed_print_idle_chk_results_wrapper(struct qed_hwfn *p_hwfn,
+                                  u32 *dump_buf,
+                                  u32 num_dumped_dwords,
+                                  char *results_buf)
 {
        u32 num_errors, num_warnnings;
 
@@ -6413,8 +6415,8 @@ static void qed_dbg_print_feature(u8 *p_text_buf, u32 text_size)
 
 #define QED_RESULTS_BUF_MIN_SIZE 16
 /* Generic function for decoding debug feature info */
-enum dbg_status format_feature(struct qed_hwfn *p_hwfn,
-                              enum qed_dbg_features feature_idx)
+static enum dbg_status format_feature(struct qed_hwfn *p_hwfn,
+                                     enum qed_dbg_features feature_idx)
 {
        struct qed_dbg_feature *feature =
            &p_hwfn->cdev->dbg_params.features[feature_idx];
@@ -6480,8 +6482,9 @@ enum dbg_status format_feature(struct qed_hwfn *p_hwfn,
 }
 
 /* Generic function for performing the dump of a debug feature. */
-enum dbg_status qed_dbg_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
-                            enum qed_dbg_features feature_idx)
+static enum dbg_status qed_dbg_dump(struct qed_hwfn *p_hwfn,
+                                   struct qed_ptt *p_ptt,
+                                   enum qed_dbg_features feature_idx)
 {
        struct qed_dbg_feature *feature =
            &p_hwfn->cdev->dbg_params.features[feature_idx];
index 754f6a908858dda8eec6f529a6281c7ba42c9ab2..edae5fc5fccddc095c6f603b2e91525378c777de 100644 (file)
@@ -497,12 +497,13 @@ int qed_resc_alloc(struct qed_dev *cdev)
                if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) {
                        num_cons = qed_cxt_get_proto_cid_count(p_hwfn,
                                                               PROTOCOLID_ROCE,
-                                                              0) * 2;
+                                                              NULL) * 2;
                        n_eqes += num_cons + 2 * MAX_NUM_VFS_BB;
                } else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
                        num_cons =
                            qed_cxt_get_proto_cid_count(p_hwfn,
-                                                       PROTOCOLID_ISCSI, 0);
+                                                       PROTOCOLID_ISCSI,
+                                                       NULL);
                        n_eqes += 2 * num_cons;
                }
 
@@ -1422,19 +1423,19 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
        u32 *feat_num = p_hwfn->hw_info.feat_num;
        int num_features = 1;
 
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
-       /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide the
-        * status blocks equally between L2 / RoCE but with consideration as
-        * to how many l2 queues / cnqs we have
-        */
-       if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) {
+       if (IS_ENABLED(CONFIG_QED_RDMA) &&
+           p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) {
+               /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide
+                * the status blocks equally between L2 / RoCE but with
+                * consideration as to how many l2 queues / cnqs we have.
+                */
                num_features++;
 
                feat_num[QED_RDMA_CNQ] =
                        min_t(u32, RESC_NUM(p_hwfn, QED_SB) / num_features,
                              RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM));
        }
-#endif
+
        feat_num[QED_PF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_SB) /
                                                num_features,
                                        RESC_NUM(p_hwfn, QED_L2_QUEUE));
index 72eee29c677f153e6ed65fbf0d57436abbe87f84..2777d5bb4380104cd4f1fcaf99ab4608b41de13f 100644 (file)
@@ -727,9 +727,6 @@ struct core_tx_bd_flags {
 #define CORE_TX_BD_FLAGS_L4_PROTOCOL_SHIFT     6
 #define CORE_TX_BD_FLAGS_L4_PSEUDO_CSUM_MODE_MASK      0x1
 #define CORE_TX_BD_FLAGS_L4_PSEUDO_CSUM_MODE_SHIFT 7
-#define CORE_TX_BD_FLAGS_ROCE_FLAV_MASK                0x1
-#define CORE_TX_BD_FLAGS_ROCE_FLAV_SHIFT       12
-
 };
 
 struct core_tx_bd {
index 02a8be2faed7fd9fdb7c66442d613f2d7c61e565..62ae55bd81b8cc2940d957e6122471e29f92a6ea 100644 (file)
@@ -38,6 +38,7 @@
 #include "qed_mcp.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
+#include "qed_roce.h"
 
 #define QED_LL2_RX_REGISTERED(ll2)     ((ll2)->rx_queue.b_cb_registred)
 #define QED_LL2_TX_REGISTERED(ll2)     ((ll2)->tx_queue.b_cb_registred)
@@ -140,11 +141,11 @@ static void qed_ll2_kill_buffers(struct qed_dev *cdev)
                qed_ll2_dealloc_buffer(cdev, buffer);
 }
 
-void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn,
-                                u8 connection_handle,
-                                struct qed_ll2_rx_packet *p_pkt,
-                                struct core_rx_fast_path_cqe *p_cqe,
-                                bool b_last_packet)
+static void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn,
+                                       u8 connection_handle,
+                                       struct qed_ll2_rx_packet *p_pkt,
+                                       struct core_rx_fast_path_cqe *p_cqe,
+                                       bool b_last_packet)
 {
        u16 packet_length = le16_to_cpu(p_cqe->packet_length);
        struct qed_ll2_buffer *buffer = p_pkt->cookie;
@@ -515,7 +516,7 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie)
        return rc;
 }
 
-void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
+static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
 {
        struct qed_ll2_info *p_ll2_conn = NULL;
        struct qed_ll2_rx_packet *p_pkt = NULL;
@@ -537,8 +538,7 @@ void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
                if (!p_pkt)
                        break;
 
-               list_del(&p_pkt->list_entry);
-               list_add_tail(&p_pkt->list_entry, &p_rx->free_descq);
+               list_move_tail(&p_pkt->list_entry, &p_rx->free_descq);
 
                rx_buf_addr = p_pkt->rx_buf_addr;
                cookie = p_pkt->cookie;
@@ -992,9 +992,8 @@ static void qed_ll2_post_rx_buffer_notify_fw(struct qed_hwfn *p_hwfn,
                p_posting_packet = list_first_entry(&p_rx->posting_descq,
                                                    struct qed_ll2_rx_packet,
                                                    list_entry);
-               list_del(&p_posting_packet->list_entry);
-               list_add_tail(&p_posting_packet->list_entry,
-                             &p_rx->active_descq);
+               list_move_tail(&p_posting_packet->list_entry,
+                              &p_rx->active_descq);
                b_notify_fw = true;
        }
 
@@ -1120,12 +1119,10 @@ static void qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn,
        start_bd->bd_flags.as_bitfield |= CORE_TX_BD_FLAGS_START_BD_MASK <<
            CORE_TX_BD_FLAGS_START_BD_SHIFT;
        SET_FIELD(start_bd->bitfield0, CORE_TX_BD_NBDS, num_of_bds);
+       SET_FIELD(start_bd->bitfield0, CORE_TX_BD_ROCE_FLAV, type);
        DMA_REGPAIR_LE(start_bd->addr, first_frag);
        start_bd->nbytes = cpu_to_le16(first_frag_len);
 
-       SET_FIELD(start_bd->bd_flags.as_bitfield, CORE_TX_BD_FLAGS_ROCE_FLAV,
-                 type);
-
        DP_VERBOSE(p_hwfn,
                   (NETIF_MSG_TX_QUEUED | QED_MSG_LL2),
                   "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n",
@@ -1188,8 +1185,7 @@ static void qed_ll2_tx_packet_notify(struct qed_hwfn *p_hwfn,
                if (!p_pkt)
                        break;
 
-               list_del(&p_pkt->list_entry);
-               list_add_tail(&p_pkt->list_entry, &p_tx->active_descq);
+               list_move_tail(&p_pkt->list_entry, &p_tx->active_descq);
        }
 
        SET_FIELD(db_msg.params, CORE_DB_DATA_DEST, DB_DEST_XCM);
@@ -1734,6 +1730,7 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb)
                                                       mapping))) {
                                DP_NOTICE(cdev,
                                          "Unable to map frag - dropping packet\n");
+                               rc = -ENOMEM;
                                goto err;
                        }
                } else {
index 80a5dc2d652d3f9b364dee97182d16bd987661d3..4e3d62a16cab7f9883aa4d4df83263c4b1de1c61 100644 (file)
@@ -293,24 +293,4 @@ void qed_ll2_setup(struct qed_hwfn *p_hwfn,
  */
 void qed_ll2_free(struct qed_hwfn *p_hwfn,
                  struct qed_ll2_info *p_ll2_connections);
-void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn,
-                                    u8 connection_handle,
-                                    void *cookie,
-                                    dma_addr_t rx_buf_addr,
-                                    u16 data_length,
-                                    u8 data_length_error,
-                                    u16 parse_flags,
-                                    u16 vlan,
-                                    u32 src_mac_addr_hi,
-                                    u16 src_mac_addr_lo, bool b_last_packet);
-void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn,
-                                    u8 connection_handle,
-                                    void *cookie,
-                                    dma_addr_t first_frag_addr,
-                                    bool b_last_fragment, bool b_last_packet);
-void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn,
-                                   u8 connection_handle,
-                                   void *cookie,
-                                   dma_addr_t first_frag_addr,
-                                   bool b_last_fragment, bool b_last_packet);
 #endif
index 4ee3151e80c244036ac5fb44bb537c15a9fb24b6..333c7442e48af451f28c37e14826d9782fa2d76a 100644 (file)
 #include "qed_hw.h"
 #include "qed_selftest.h"
 
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
 #define QED_ROCE_QPS                   (8192)
 #define QED_ROCE_DPIS                  (8)
-#endif
 
 static char version[] =
        "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n";
@@ -682,9 +680,7 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev,
                                  enum qed_int_mode int_mode)
 {
        struct qed_sb_cnt_info sb_cnt_info;
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
-       int num_l2_queues;
-#endif
+       int num_l2_queues = 0;
        int rc;
        int i;
 
@@ -715,8 +711,9 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev,
        cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors -
                                       cdev->num_hwfns;
 
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
-       num_l2_queues = 0;
+       if (!IS_ENABLED(CONFIG_QED_RDMA))
+               return 0;
+
        for_each_hwfn(cdev, i)
                num_l2_queues += FEAT_NUM(&cdev->hwfns[i], QED_PF_L2_QUE);
 
@@ -738,7 +735,6 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev,
        DP_VERBOSE(cdev, QED_MSG_RDMA, "roce_msix_cnt=%d roce_msix_base=%d\n",
                   cdev->int_params.rdma_msix_cnt,
                   cdev->int_params.rdma_msix_base);
-#endif
 
        return 0;
 }
@@ -843,13 +839,14 @@ static void qed_update_pf_params(struct qed_dev *cdev,
 {
        int i;
 
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
-       params->rdma_pf_params.num_qps = QED_ROCE_QPS;
-       params->rdma_pf_params.min_dpis = QED_ROCE_DPIS;
-       /* divide by 3 the MRs to avoid MF ILT overflow */
-       params->rdma_pf_params.num_mrs = RDMA_MAX_TIDS;
-       params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX;
-#endif
+       if (IS_ENABLED(CONFIG_QED_RDMA)) {
+               params->rdma_pf_params.num_qps = QED_ROCE_QPS;
+               params->rdma_pf_params.min_dpis = QED_ROCE_DPIS;
+               /* divide by 3 the MRs to avoid MF ILT overflow */
+               params->rdma_pf_params.num_mrs = RDMA_MAX_TIDS;
+               params->rdma_pf_params.gl_pi = QED_ROCE_PROTOCOL_INDEX;
+       }
+
        for (i = 0; i < cdev->num_hwfns; i++) {
                struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
 
@@ -880,6 +877,7 @@ static int qed_slowpath_start(struct qed_dev *cdev,
                }
        }
 
+       cdev->rx_coalesce_usecs = QED_DEFAULT_RX_USECS;
        rc = qed_nic_setup(cdev);
        if (rc)
                goto err;
@@ -1432,7 +1430,7 @@ static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode)
        return status;
 }
 
-struct qed_selftest_ops qed_selftest_ops_pass = {
+static struct qed_selftest_ops qed_selftest_ops_pass = {
        .selftest_memory = &qed_selftest_memory,
        .selftest_interrupt = &qed_selftest_interrupt,
        .selftest_register = &qed_selftest_register,
index 76831a398bedf024d299db1ffb68c1149664ace1..f3a825a8f8d52dda6aff03074e61c830370d0594 100644 (file)
@@ -129,17 +129,12 @@ static void qed_bmap_release_id(struct qed_hwfn *p_hwfn,
        }
 }
 
-u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id)
+static u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id)
 {
        /* First sb id for RoCE is after all the l2 sb */
        return FEAT_NUM((struct qed_hwfn *)p_hwfn, QED_PF_L2_QUE) + rel_sb_id;
 }
 
-u32 qed_rdma_query_cau_timer_res(void *rdma_cxt)
-{
-       return QED_CAU_DEF_RX_TIMER_RES;
-}
-
 static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
                          struct qed_ptt *p_ptt,
                          struct qed_rdma_start_in_params *params)
@@ -162,7 +157,8 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
        p_hwfn->p_rdma_info = p_rdma_info;
        p_rdma_info->proto = PROTOCOLID_ROCE;
 
-       num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto, 0);
+       num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto,
+                                              NULL);
 
        p_rdma_info->num_qps = num_cons / 2;
 
@@ -275,7 +271,7 @@ free_rdma_info:
        return rc;
 }
 
-void qed_rdma_resc_free(struct qed_hwfn *p_hwfn)
+static void qed_rdma_resc_free(struct qed_hwfn *p_hwfn)
 {
        struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info;
 
@@ -527,6 +523,26 @@ static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn,
        return qed_spq_post(p_hwfn, p_ent, NULL);
 }
 
+static int qed_rdma_alloc_tid(void *rdma_cxt, u32 *itid)
+{
+       struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
+       int rc;
+
+       DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID\n");
+
+       spin_lock_bh(&p_hwfn->p_rdma_info->lock);
+       rc = qed_rdma_bmap_alloc_id(p_hwfn,
+                                   &p_hwfn->p_rdma_info->tid_map, itid);
+       spin_unlock_bh(&p_hwfn->p_rdma_info->lock);
+       if (rc)
+               goto out;
+
+       rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_TASK, *itid);
+out:
+       DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID - done, rc = %d\n", rc);
+       return rc;
+}
+
 static int qed_rdma_reserve_lkey(struct qed_hwfn *p_hwfn)
 {
        struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev;
@@ -573,7 +589,7 @@ static int qed_rdma_setup(struct qed_hwfn *p_hwfn,
        return qed_rdma_start_fw(p_hwfn, params, p_ptt);
 }
 
-int qed_rdma_stop(void *rdma_cxt)
+static int qed_rdma_stop(void *rdma_cxt)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        struct rdma_close_func_ramrod_data *p_ramrod;
@@ -629,8 +645,8 @@ out:
        return rc;
 }
 
-int qed_rdma_add_user(void *rdma_cxt,
-                     struct qed_rdma_add_user_out_params *out_params)
+static int qed_rdma_add_user(void *rdma_cxt,
+                            struct qed_rdma_add_user_out_params *out_params)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        u32 dpi_start_offset;
@@ -664,7 +680,7 @@ int qed_rdma_add_user(void *rdma_cxt,
        return rc;
 }
 
-struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt)
+static struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        struct qed_rdma_port *p_port = p_hwfn->p_rdma_info->port;
@@ -680,7 +696,7 @@ struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt)
        return p_port;
 }
 
-struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt)
+static struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
 
@@ -690,7 +706,7 @@ struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt)
        return p_hwfn->p_rdma_info->dev;
 }
 
-void qed_rdma_free_tid(void *rdma_cxt, u32 itid)
+static void qed_rdma_free_tid(void *rdma_cxt, u32 itid)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
 
@@ -701,27 +717,7 @@ void qed_rdma_free_tid(void *rdma_cxt, u32 itid)
        spin_unlock_bh(&p_hwfn->p_rdma_info->lock);
 }
 
-int qed_rdma_alloc_tid(void *rdma_cxt, u32 *itid)
-{
-       struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
-       int rc;
-
-       DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID\n");
-
-       spin_lock_bh(&p_hwfn->p_rdma_info->lock);
-       rc = qed_rdma_bmap_alloc_id(p_hwfn,
-                                   &p_hwfn->p_rdma_info->tid_map, itid);
-       spin_unlock_bh(&p_hwfn->p_rdma_info->lock);
-       if (rc)
-               goto out;
-
-       rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_TASK, *itid);
-out:
-       DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID - done, rc = %d\n", rc);
-       return rc;
-}
-
-void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod)
+static void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod)
 {
        struct qed_hwfn *p_hwfn;
        u16 qz_num;
@@ -816,7 +812,7 @@ static int qed_rdma_get_int(struct qed_dev *cdev, struct qed_int_info *info)
        return 0;
 }
 
-int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd)
+static int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        u32 returned_id;
@@ -836,7 +832,7 @@ int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd)
        return rc;
 }
 
-void qed_rdma_free_pd(void *rdma_cxt, u16 pd)
+static void qed_rdma_free_pd(void *rdma_cxt, u16 pd)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
 
@@ -873,8 +869,9 @@ qed_rdma_toggle_bit_create_resize_cq(struct qed_hwfn *p_hwfn, u16 icid)
        return toggle_bit;
 }
 
-int qed_rdma_create_cq(void *rdma_cxt,
-                      struct qed_rdma_create_cq_in_params *params, u16 *icid)
+static int qed_rdma_create_cq(void *rdma_cxt,
+                             struct qed_rdma_create_cq_in_params *params,
+                             u16 *icid)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        struct qed_rdma_info *p_info = p_hwfn->p_rdma_info;
@@ -957,98 +954,10 @@ err:
        return rc;
 }
 
-int qed_rdma_resize_cq(void *rdma_cxt,
-                      struct qed_rdma_resize_cq_in_params *in_params,
-                      struct qed_rdma_resize_cq_out_params *out_params)
-{
-       struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
-       struct rdma_resize_cq_output_params *p_ramrod_res;
-       struct rdma_resize_cq_ramrod_data *p_ramrod;
-       enum qed_rdma_toggle_bit toggle_bit;
-       struct qed_sp_init_data init_data;
-       struct qed_spq_entry *p_ent;
-       dma_addr_t ramrod_res_phys;
-       u8 fw_return_code;
-       int rc = -ENOMEM;
-
-       DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", in_params->icid);
-
-       p_ramrod_res =
-           (struct rdma_resize_cq_output_params *)
-           dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
-                              sizeof(struct rdma_resize_cq_output_params),
-                              &ramrod_res_phys, GFP_KERNEL);
-       if (!p_ramrod_res) {
-               DP_NOTICE(p_hwfn,
-                         "qed resize cq failed: cannot allocate memory (ramrod)\n");
-               return rc;
-       }
-
-       /* Get SPQ entry */
-       memset(&init_data, 0, sizeof(init_data));
-       init_data.cid = in_params->icid;
-       init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
-       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
-
-       rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                RDMA_RAMROD_RESIZE_CQ,
-                                p_hwfn->p_rdma_info->proto, &init_data);
-       if (rc)
-               goto err;
-
-       p_ramrod = &p_ent->ramrod.rdma_resize_cq;
-
-       p_ramrod->flags = 0;
-
-       /* toggle the bit for every resize or create cq for a given icid */
-       toggle_bit = qed_rdma_toggle_bit_create_resize_cq(p_hwfn,
-                                                         in_params->icid);
-
-       SET_FIELD(p_ramrod->flags,
-                 RDMA_RESIZE_CQ_RAMROD_DATA_TOGGLE_BIT, toggle_bit);
-
-       SET_FIELD(p_ramrod->flags,
-                 RDMA_RESIZE_CQ_RAMROD_DATA_IS_TWO_LEVEL_PBL,
-                 in_params->pbl_two_level);
-
-       p_ramrod->pbl_log_page_size = in_params->pbl_page_size_log - 12;
-       p_ramrod->pbl_num_pages = cpu_to_le16(in_params->pbl_num_pages);
-       p_ramrod->max_cqes = cpu_to_le32(in_params->cq_size);
-       DMA_REGPAIR_LE(p_ramrod->pbl_addr, in_params->pbl_ptr);
-       DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys);
-
-       rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code);
-       if (rc)
-               goto err;
-
-       if (fw_return_code != RDMA_RETURN_OK) {
-               DP_NOTICE(p_hwfn, "fw_return_code = %d\n", fw_return_code);
-               rc = -EINVAL;
-               goto err;
-       }
-
-       out_params->prod = le32_to_cpu(p_ramrod_res->old_cq_prod);
-       out_params->cons = le32_to_cpu(p_ramrod_res->old_cq_cons);
-
-       dma_free_coherent(&p_hwfn->cdev->pdev->dev,
-                         sizeof(struct rdma_resize_cq_output_params),
-                         p_ramrod_res, ramrod_res_phys);
-
-       DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Resized CQ, rc = %d\n", rc);
-
-       return rc;
-
-err:   dma_free_coherent(&p_hwfn->cdev->pdev->dev,
-                         sizeof(struct rdma_resize_cq_output_params),
-                         p_ramrod_res, ramrod_res_phys);
-       DP_NOTICE(p_hwfn, "Resized CQ, Failed - rc = %d\n", rc);
-
-       return rc;
-}
-
-int qed_rdma_destroy_cq(void *rdma_cxt,
-                       struct qed_rdma_destroy_cq_in_params *in_params,
-                       struct qed_rdma_destroy_cq_out_params *out_params)
+static int
+qed_rdma_destroy_cq(void *rdma_cxt,
+                   struct qed_rdma_destroy_cq_in_params *in_params,
+                   struct qed_rdma_destroy_cq_out_params *out_params)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        struct rdma_destroy_cq_output_params *p_ramrod_res;
@@ -1169,7 +1078,7 @@ static enum roce_flavor qed_roce_mode_to_flavor(enum roce_mode roce_mode)
        return flavor;
 }
 
-int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid)
+static int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid)
 {
        struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info;
        u32 responder_icid;
@@ -1793,9 +1702,9 @@ err:
        return rc;
 }
 
-int qed_roce_query_qp(struct qed_hwfn *p_hwfn,
-                     struct qed_rdma_qp *qp,
-                     struct qed_rdma_query_qp_out_params *out_params)
+static int qed_roce_query_qp(struct qed_hwfn *p_hwfn,
+                            struct qed_rdma_qp *qp,
+                            struct qed_rdma_query_qp_out_params *out_params)
 {
        struct roce_query_qp_resp_output_params *p_resp_ramrod_res;
        struct roce_query_qp_req_output_params *p_req_ramrod_res;
@@ -1936,7 +1845,7 @@ err_resp:
        return rc;
 }
 
-int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp)
+static int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp)
 {
        u32 num_invalidated_mw = 0;
        u32 num_bound_mw = 0;
@@ -1985,9 +1894,9 @@ int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp)
        return 0;
 }
 
-int qed_rdma_query_qp(void *rdma_cxt,
-                     struct qed_rdma_qp *qp,
-                     struct qed_rdma_query_qp_out_params *out_params)
+static int qed_rdma_query_qp(void *rdma_cxt,
+                            struct qed_rdma_qp *qp,
+                            struct qed_rdma_query_qp_out_params *out_params)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        int rc;
@@ -2022,7 +1931,7 @@ int qed_rdma_query_qp(void *rdma_cxt,
        return rc;
 }
 
-int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp)
+static int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        int rc = 0;
@@ -2038,7 +1947,7 @@ int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp)
        return rc;
 }
 
-struct qed_rdma_qp *
+static struct qed_rdma_qp *
 qed_rdma_create_qp(void *rdma_cxt,
                   struct qed_rdma_create_qp_in_params *in_params,
                   struct qed_rdma_create_qp_out_params *out_params)
@@ -2215,9 +2124,9 @@ static int qed_roce_modify_qp(struct qed_hwfn *p_hwfn,
        return rc;
 }
 
-int qed_rdma_modify_qp(void *rdma_cxt,
-                      struct qed_rdma_qp *qp,
-                      struct qed_rdma_modify_qp_in_params *params)
+static int qed_rdma_modify_qp(void *rdma_cxt,
+                             struct qed_rdma_qp *qp,
+                             struct qed_rdma_modify_qp_in_params *params)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        enum qed_roce_qp_state prev_state;
@@ -2312,8 +2221,9 @@ int qed_rdma_modify_qp(void *rdma_cxt,
        return rc;
 }
 
-int qed_rdma_register_tid(void *rdma_cxt,
-                         struct qed_rdma_register_tid_in_params *params)
+static int
+qed_rdma_register_tid(void *rdma_cxt,
+                     struct qed_rdma_register_tid_in_params *params)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        struct rdma_register_tid_ramrod_data *p_ramrod;
@@ -2450,7 +2360,7 @@ int qed_rdma_register_tid(void *rdma_cxt,
        return rc;
 }
 
-int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid)
+static int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        struct rdma_deregister_tid_ramrod_data *p_ramrod;
@@ -2561,7 +2471,8 @@ void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
        qed_rdma_dpm_conf(p_hwfn, p_ptt);
 }
 
-int qed_rdma_start(void *rdma_cxt, struct qed_rdma_start_in_params *params)
+static int qed_rdma_start(void *rdma_cxt,
+                         struct qed_rdma_start_in_params *params)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
        struct qed_ptt *p_ptt;
@@ -2601,7 +2512,7 @@ static int qed_rdma_init(struct qed_dev *cdev,
        return qed_rdma_start(QED_LEADING_HWFN(cdev), params);
 }
 
-void qed_rdma_remove_user(void *rdma_cxt, u16 dpi)
+static void qed_rdma_remove_user(void *rdma_cxt, u16 dpi)
 {
        struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
 
@@ -2809,11 +2720,6 @@ static int qed_roce_ll2_stop(struct qed_dev *cdev)
        struct qed_roce_ll2_info *roce_ll2 = hwfn->ll2;
        int rc;
 
-       if (!cdev) {
-               DP_ERR(cdev, "qed roce ll2 stop: invalid cdev\n");
-               return -EINVAL;
-       }
-
        if (roce_ll2->handle == QED_LL2_UNUSED_HANDLE) {
                DP_ERR(cdev, "qed roce ll2 stop: cannot stop an unused LL2\n");
                return -EINVAL;
@@ -2850,7 +2756,7 @@ static int qed_roce_ll2_tx(struct qed_dev *cdev,
        int rc;
        int i;
 
-       if (!cdev || !pkt || !params) {
+       if (!pkt || !params) {
                DP_ERR(cdev,
                       "roce ll2 tx: failed tx because one of the following is NULL - drv=%p, pkt=%p, params=%p\n",
                       cdev, pkt, params);
index 2f091e8a0f40b7bb266e24ab183da88a5135c56e..279f342af8db1c91272fa89bf80fbde565f5e135 100644 (file)
@@ -95,26 +95,6 @@ struct qed_rdma_info {
        enum protocol_type proto;
 };
 
-struct qed_rdma_resize_cq_in_params {
-       u16 icid;
-       u32 cq_size;
-       bool pbl_two_level;
-       u64 pbl_ptr;
-       u16 pbl_num_pages;
-       u8 pbl_page_size_log;
-};
-
-struct qed_rdma_resize_cq_out_params {
-       u32 prod;
-       u32 cons;
-};
-
-struct qed_rdma_resize_cnq_in_params {
-       u32 cnq_id;
-       u32 pbl_page_size_log;
-       u64 pbl_ptr;
-};
-
 struct qed_rdma_qp {
        struct regpair qp_handle;
        struct regpair qp_handle_async;
@@ -181,36 +161,55 @@ struct qed_rdma_qp {
        dma_addr_t shared_queue_phys_addr;
 };
 
-int
-qed_rdma_add_user(void *rdma_cxt,
-                 struct qed_rdma_add_user_out_params *out_params);
-int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd);
-int qed_rdma_alloc_tid(void *rdma_cxt, u32 *tid);
-int qed_rdma_deregister_tid(void *rdma_cxt, u32 tid);
-void qed_rdma_free_tid(void *rdma_cxt, u32 tid);
-struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt);
-struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt);
-int
-qed_rdma_register_tid(void *rdma_cxt,
-                     struct qed_rdma_register_tid_in_params *params);
-void qed_rdma_remove_user(void *rdma_cxt, u16 dpi);
-int qed_rdma_start(void *p_hwfn, struct qed_rdma_start_in_params *params);
-int qed_rdma_stop(void *rdma_cxt);
-u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id);
-u32 qed_rdma_query_cau_timer_res(void *p_hwfn);
-void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 cnq_index, u16 prod);
-void qed_rdma_resc_free(struct qed_hwfn *p_hwfn);
+#if IS_ENABLED(CONFIG_QED_RDMA)
+void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 void qed_async_roce_event(struct qed_hwfn *p_hwfn,
                          struct event_ring_entry *p_eqe);
-int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp);
-int qed_rdma_modify_qp(void *rdma_cxt, struct qed_rdma_qp *qp,
-                      struct qed_rdma_modify_qp_in_params *params);
-int qed_rdma_query_qp(void *rdma_cxt, struct qed_rdma_qp *qp,
-                     struct qed_rdma_query_qp_out_params *out_params);
-
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
-void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
+void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn,
+                                    u8 connection_handle,
+                                    void *cookie,
+                                    dma_addr_t first_frag_addr,
+                                    bool b_last_fragment, bool b_last_packet);
+void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn,
+                                   u8 connection_handle,
+                                   void *cookie,
+                                   dma_addr_t first_frag_addr,
+                                   bool b_last_fragment, bool b_last_packet);
+void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn,
+                                    u8 connection_handle,
+                                    void *cookie,
+                                    dma_addr_t rx_buf_addr,
+                                    u16 data_length,
+                                    u8 data_length_error,
+                                    u16 parse_flags,
+                                    u16 vlan,
+                                    u32 src_mac_addr_hi,
+                                    u16 src_mac_addr_lo, bool b_last_packet);
 #else
-void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {}
+static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {}
+static inline void qed_async_roce_event(struct qed_hwfn *p_hwfn, struct event_ring_entry *p_eqe) {}
+static inline void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn,
+                                                  u8 connection_handle,
+                                                  void *cookie,
+                                                  dma_addr_t first_frag_addr,
+                                                  bool b_last_fragment,
+                                                  bool b_last_packet) {}
+static inline void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn,
+                                                 u8 connection_handle,
+                                                 void *cookie,
+                                                 dma_addr_t first_frag_addr,
+                                                 bool b_last_fragment,
+                                                 bool b_last_packet) {}
+static inline void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn,
+                                                  u8 connection_handle,
+                                                  void *cookie,
+                                                  dma_addr_t rx_buf_addr,
+                                                  u16 data_length,
+                                                  u8 data_length_error,
+                                                  u16 parse_flags,
+                                                  u16 vlan,
+                                                  u32 src_mac_addr_hi,
+                                                  u16 src_mac_addr_lo,
+                                                  bool b_last_packet) {}
 #endif
 #endif
index 652c908197582a09ee648b55706d15bfdedbb372..b2c08e4d2a9b9de9c2042bc2afa22c6bd51c3618 100644 (file)
@@ -80,7 +80,6 @@ union ramrod_data {
        struct roce_destroy_qp_resp_ramrod_data roce_destroy_qp_resp;
        struct roce_destroy_qp_req_ramrod_data roce_destroy_qp_req;
        struct rdma_create_cq_ramrod_data rdma_create_cq;
-       struct rdma_resize_cq_ramrod_data rdma_resize_cq;
        struct rdma_destroy_cq_ramrod_data rdma_destroy_cq;
        struct rdma_srq_create_ramrod_data rdma_create_srq;
        struct rdma_srq_destroy_ramrod_data rdma_destroy_srq;
index caff41544898baed09f45a41829cb0ba9c719fb9..9fbaf9429fd0a20c2e48616e2397c70f38fd3d14 100644 (file)
@@ -28,9 +28,7 @@
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
 #include "qed_sriov.h"
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
 #include "qed_roce.h"
-#endif
 
 /***************************************************************************
 * Structures & Definitions
@@ -240,11 +238,9 @@ qed_async_event_completion(struct qed_hwfn *p_hwfn,
                           struct event_ring_entry *p_eqe)
 {
        switch (p_eqe->protocol_id) {
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
        case PROTOCOLID_ROCE:
                qed_async_roce_event(p_hwfn, p_eqe);
                return 0;
-#endif
        case PROTOCOLID_COMMON:
                return qed_sriov_eqe_event(p_hwfn,
                                           p_eqe->opcode,
index 28dc58919c851f008aebbfca750dbbe962b97d48..048a230c3ce0c5bc807bc52a7484f6b53a2438b2 100644 (file)
@@ -2,4 +2,4 @@ obj-$(CONFIG_QEDE) := qede.o
 
 qede-y := qede_main.o qede_ethtool.o
 qede-$(CONFIG_DCB) += qede_dcbnl.o
-qede-$(CONFIG_INFINIBAND_QEDR) += qede_roce.o
+qede-$(CONFIG_QED_RDMA) += qede_roce.o
index 28c0e9f42c9e777611ab085249a2efc74201a6e6..974689a133372152238e1cd3033a1838222c1bc5 100644 (file)
@@ -348,12 +348,13 @@ bool qede_has_rx_work(struct qede_rx_queue *rxq);
 int qede_txq_has_work(struct qede_tx_queue *txq);
 void qede_recycle_rx_bd_ring(struct qede_rx_queue *rxq, struct qede_dev *edev,
                             u8 count);
+void qede_update_rx_prod(struct qede_dev *edev, struct qede_rx_queue *rxq);
 
 #define RX_RING_SIZE_POW       13
 #define RX_RING_SIZE           ((u16)BIT(RX_RING_SIZE_POW))
 #define NUM_RX_BDS_MAX         (RX_RING_SIZE - 1)
 #define NUM_RX_BDS_MIN         128
-#define NUM_RX_BDS_DEF         NUM_RX_BDS_MAX
+#define NUM_RX_BDS_DEF         ((u16)BIT(10) - 1)
 
 #define TX_RING_SIZE_POW       13
 #define TX_RING_SIZE           ((u16)BIT(TX_RING_SIZE_POW))
index 25a9b293ee8f8cf2352f8d90c34c816be3edecba..7567cc464b88b6b04ba15c6ceb7f4e6ace759af8 100644 (file)
@@ -175,16 +175,23 @@ static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
        for (i = 0, k = 0; i < QEDE_QUEUE_CNT(edev); i++) {
                int tc;
 
-               for (j = 0; j < QEDE_NUM_RQSTATS; j++)
-                       sprintf(buf + (k + j) * ETH_GSTRING_LEN,
-                               "%d:   %s", i, qede_rqstats_arr[j].string);
-               k += QEDE_NUM_RQSTATS;
-               for (tc = 0; tc < edev->num_tc; tc++) {
-                       for (j = 0; j < QEDE_NUM_TQSTATS; j++)
+               if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
+                       for (j = 0; j < QEDE_NUM_RQSTATS; j++)
                                sprintf(buf + (k + j) * ETH_GSTRING_LEN,
-                                       "%d.%d: %s", i, tc,
-                                       qede_tqstats_arr[j].string);
-                       k += QEDE_NUM_TQSTATS;
+                                       "%d:   %s", i,
+                                       qede_rqstats_arr[j].string);
+                       k += QEDE_NUM_RQSTATS;
+               }
+
+               if (edev->fp_array[i].type & QEDE_FASTPATH_TX) {
+                       for (tc = 0; tc < edev->num_tc; tc++) {
+                               for (j = 0; j < QEDE_NUM_TQSTATS; j++)
+                                       sprintf(buf + (k + j) *
+                                               ETH_GSTRING_LEN,
+                                               "%d.%d: %s", i, tc,
+                                               qede_tqstats_arr[j].string);
+                               k += QEDE_NUM_TQSTATS;
+                       }
                }
        }
 
@@ -756,6 +763,8 @@ static void qede_get_channels(struct net_device *dev,
        struct qede_dev *edev = netdev_priv(dev);
 
        channels->max_combined = QEDE_MAX_RSS_CNT(edev);
+       channels->max_rx = QEDE_MAX_RSS_CNT(edev);
+       channels->max_tx = QEDE_MAX_RSS_CNT(edev);
        channels->combined_count = QEDE_QUEUE_CNT(edev) - edev->fp_num_tx -
                                        edev->fp_num_rx;
        channels->tx_count = edev->fp_num_tx;
@@ -820,6 +829,13 @@ static int qede_set_channels(struct net_device *dev,
        edev->req_queues = count;
        edev->req_num_tx = channels->tx_count;
        edev->req_num_rx = channels->rx_count;
+       /* Reset the indirection table if rx queue count is updated */
+       if ((edev->req_queues - edev->req_num_tx) != QEDE_RSS_COUNT(edev)) {
+               edev->rss_params_inited &= ~QEDE_RSS_INDIR_INITED;
+               memset(&edev->rss_params.rss_ind_table, 0,
+                      sizeof(edev->rss_params.rss_ind_table));
+       }
+
        if (netif_running(dev))
                qede_reload(edev, NULL, NULL);
 
@@ -1053,6 +1069,12 @@ static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
        struct qede_dev *edev = netdev_priv(dev);
        int i;
 
+       if (edev->dev_info.common.num_hwfns > 1) {
+               DP_INFO(edev,
+                       "RSS configuration is not supported for 100G devices\n");
+               return -EOPNOTSUPP;
+       }
+
        if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
                return -EOPNOTSUPP;
 
@@ -1184,8 +1206,8 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev,
        }
 
        first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl);
-       dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
-                      BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE);
+       dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
+                        BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE);
        txq->sw_tx_cons++;
        txq->sw_tx_ring[idx].skb = NULL;
 
@@ -1199,8 +1221,8 @@ static int qede_selftest_receive_traffic(struct qede_dev *edev)
        struct qede_rx_queue *rxq = NULL;
        struct sw_rx_data *sw_rx_data;
        union eth_rx_cqe *cqe;
+       int i, rc = 0;
        u8 *data_ptr;
-       int i;
 
        for_each_queue(i) {
                if (edev->fp_array[i].type & QEDE_FASTPATH_RX) {
@@ -1219,46 +1241,60 @@ static int qede_selftest_receive_traffic(struct qede_dev *edev)
         * queue and that the loopback traffic is not IP.
         */
        for (i = 0; i < QEDE_SELFTEST_POLL_COUNT; i++) {
-               if (qede_has_rx_work(rxq))
+               if (!qede_has_rx_work(rxq)) {
+                       usleep_range(100, 200);
+                       continue;
+               }
+
+               hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr);
+               sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
+
+               /* Memory barrier to prevent the CPU from doing speculative
+                * reads of CQE/BD before reading hw_comp_cons. If the CQE is
+                * read before it is written by FW, then FW writes CQE and SB,
+                * and then the CPU reads the hw_comp_cons, it will use an old
+                * CQE.
+                */
+               rmb();
+
+               /* Get the CQE from the completion ring */
+               cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring);
+
+               /* Get the data from the SW ring */
+               sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
+               sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
+               fp_cqe = &cqe->fast_path_regular;
+               len =  le16_to_cpu(fp_cqe->len_on_first_bd);
+               data_ptr = (u8 *)(page_address(sw_rx_data->data) +
+                                 fp_cqe->placement_offset +
+                                 sw_rx_data->page_offset);
+               if (ether_addr_equal(data_ptr,  edev->ndev->dev_addr) &&
+                   ether_addr_equal(data_ptr + ETH_ALEN,
+                                    edev->ndev->dev_addr)) {
+                       for (i = ETH_HLEN; i < len; i++)
+                               if (data_ptr[i] != (unsigned char)(i & 0xff)) {
+                                       rc = -1;
+                                       break;
+                               }
+
+                       qede_recycle_rx_bd_ring(rxq, edev, 1);
+                       qed_chain_recycle_consumed(&rxq->rx_comp_ring);
                        break;
-               usleep_range(100, 200);
+               }
+
+               DP_INFO(edev, "Not the transmitted packet\n");
+               qede_recycle_rx_bd_ring(rxq, edev, 1);
+               qed_chain_recycle_consumed(&rxq->rx_comp_ring);
        }
 
-       if (!qede_has_rx_work(rxq)) {
+       if (i == QEDE_SELFTEST_POLL_COUNT) {
                DP_NOTICE(edev, "Failed to receive the traffic\n");
                return -1;
        }
 
-       hw_comp_cons = le16_to_cpu(*rxq->hw_cons_ptr);
-       sw_comp_cons = qed_chain_get_cons_idx(&rxq->rx_comp_ring);
+       qede_update_rx_prod(edev, rxq);
 
-       /* Memory barrier to prevent the CPU from doing speculative reads of CQE
-        * / BD before reading hw_comp_cons. If the CQE is read before it is
-        * written by FW, then FW writes CQE and SB, and then the CPU reads the
-        * hw_comp_cons, it will use an old CQE.
-        */
-       rmb();
-
-       /* Get the CQE from the completion ring */
-       cqe = (union eth_rx_cqe *)qed_chain_consume(&rxq->rx_comp_ring);
-
-       /* Get the data from the SW ring */
-       sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
-       sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
-       fp_cqe = &cqe->fast_path_regular;
-       len =  le16_to_cpu(fp_cqe->len_on_first_bd);
-       data_ptr = (u8 *)(page_address(sw_rx_data->data) +
-                    fp_cqe->placement_offset + sw_rx_data->page_offset);
-       for (i = ETH_HLEN; i < len; i++)
-               if (data_ptr[i] != (unsigned char)(i & 0xff)) {
-                       DP_NOTICE(edev, "Loopback test failed\n");
-                       qede_recycle_rx_bd_ring(rxq, edev, 1);
-                       return -1;
-               }
-
-       qede_recycle_rx_bd_ring(rxq, edev, 1);
-
-       return 0;
+       return rc;
 }
 
 static int qede_selftest_run_loopback(struct qede_dev *edev, u32 loopback_mode)
index 343038ca047d7ed79369a271c0d13d6ca6b80567..85f46dbecd5b57b5cdb537900a51dbd8cfa4dcc1 100644 (file)
@@ -313,8 +313,8 @@ static int qede_free_tx_pkt(struct qede_dev *edev,
                split_bd_len = BD_UNMAP_LEN(split);
                bds_consumed++;
        }
-       dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
-                      BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE);
+       dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
+                        BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE);
 
        /* Unmap the data of the skb frags */
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, bds_consumed++) {
@@ -359,8 +359,8 @@ static void qede_free_failed_tx_pkt(struct qede_dev *edev,
                nbd--;
        }
 
-       dma_unmap_page(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
-                      BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE);
+       dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
+                        BD_UNMAP_LEN(first_bd) + split_bd_len, DMA_TO_DEVICE);
 
        /* Unmap the data of the skb frags */
        for (i = 0; i < nbd; i++) {
@@ -943,8 +943,7 @@ static inline int qede_realloc_rx_buffer(struct qede_dev *edev,
        return 0;
 }
 
-static inline void qede_update_rx_prod(struct qede_dev *edev,
-                                      struct qede_rx_queue *rxq)
+void qede_update_rx_prod(struct qede_dev *edev, struct qede_rx_queue *rxq)
 {
        u16 bd_prod = qed_chain_get_prod_idx(&rxq->rx_bd_ring);
        u16 cqe_prod = qed_chain_get_prod_idx(&rxq->rx_comp_ring);
@@ -2840,7 +2839,7 @@ static int qede_alloc_sge_mem(struct qede_dev *edev, struct qede_rx_queue *rxq)
                }
 
                mapping = dma_map_page(&edev->pdev->dev, replace_buf->data, 0,
-                                      rxq->rx_buf_size, DMA_FROM_DEVICE);
+                                      PAGE_SIZE, DMA_FROM_DEVICE);
                if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) {
                        DP_NOTICE(edev,
                                  "Failed to map TPA replacement buffer\n");
@@ -2941,7 +2940,7 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
        txq->num_tx_buffers = edev->q_num_tx_buffers;
 
        /* Allocate the parallel driver ring for Tx buffers */
-       size = sizeof(*txq->sw_tx_ring) * NUM_TX_BDS_MAX;
+       size = sizeof(*txq->sw_tx_ring) * TX_RING_SIZE;
        txq->sw_tx_ring = kzalloc(size, GFP_KERNEL);
        if (!txq->sw_tx_ring) {
                DP_NOTICE(edev, "Tx buffers ring allocation failed\n");
@@ -2952,7 +2951,7 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
                                            QED_CHAIN_USE_TO_CONSUME_PRODUCE,
                                            QED_CHAIN_MODE_PBL,
                                            QED_CHAIN_CNT_TYPE_U16,
-                                           NUM_TX_BDS_MAX,
+                                           TX_RING_SIZE,
                                            sizeof(*p_virt), &txq->tx_pbl);
        if (rc)
                goto err;
index e97968ed4b8f7294cf6869ab4351711b8d9f55e5..0b4deb31e742fc4d48a2f91e865d7d750e0023c2 100644 (file)
@@ -575,10 +575,11 @@ void emac_mac_start(struct emac_adapter *adpt)
 
        mac |= TXEN | RXEN;     /* enable RX/TX */
 
-       /* We don't have ethtool support yet, so force flow-control mode
-        * to 'full' always.
-        */
-       mac |= TXFC | RXFC;
+       /* Configure MAC flow control to match the PHY's settings. */
+       if (phydev->pause)
+               mac |= RXFC;
+       if (phydev->pause != phydev->asym_pause)
+               mac |= TXFC;
 
        /* setup link speed */
        mac &= ~SPEED_MASK;
@@ -1003,6 +1004,12 @@ int emac_mac_up(struct emac_adapter *adpt)
        writel((u32)~DIS_INT, adpt->base + EMAC_INT_STATUS);
        writel(adpt->irq.mask, adpt->base + EMAC_INT_MASK);
 
+       /* Enable pause frames.  Without this feature, the EMAC has been shown
+        * to receive (and drop) frames with FCS errors at gigabit connections.
+        */
+       adpt->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+       adpt->phydev->advertising |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
        adpt->phydev->irq = PHY_IGNORE_INTERRUPT;
        phy_start(adpt->phydev);
 
@@ -1021,14 +1028,18 @@ void emac_mac_down(struct emac_adapter *adpt)
        napi_disable(&adpt->rx_q.napi);
 
        phy_stop(adpt->phydev);
-       phy_disconnect(adpt->phydev);
 
-       /* disable mac irq */
+       /* Interrupts must be disabled before the PHY is disconnected, to
+        * avoid a race condition where adjust_link is null when we get
+        * an interrupt.
+        */
        writel(DIS_INT, adpt->base + EMAC_INT_STATUS);
        writel(0, adpt->base + EMAC_INT_MASK);
        synchronize_irq(adpt->irq.irq);
        free_irq(adpt->irq.irq, &adpt->irq);
 
+       phy_disconnect(adpt->phydev);
+
        emac_mac_reset(adpt);
 
        emac_tx_q_descs_free(adpt);
index da4e90db4d989a7d9f74c45279ca36cb675b20bc..99a14df28b9634dd8e6fdeb6bc9bce2d219a3e1a 100644 (file)
@@ -212,6 +212,7 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt)
 
                phy_np = of_parse_phandle(np, "phy-handle", 0);
                adpt->phydev = of_phy_find_device(phy_np);
+               of_node_put(phy_np);
        }
 
        if (!adpt->phydev) {
index 75c1b530e39e8118f1788d0647988b97df260d23..72fe343c7a368d23de6c19f922add549aa1043f7 100644 (file)
@@ -421,7 +421,7 @@ static const struct emac_reg_write sgmii_v2_laned[] = {
        /* CDR Settings */
        {EMAC_SGMII_LN_UCDR_FO_GAIN_MODE0,
                UCDR_STEP_BY_TWO_MODE0 | UCDR_xO_GAIN_MODE(10)},
-       {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(6)},
+       {EMAC_SGMII_LN_UCDR_SO_GAIN_MODE0, UCDR_xO_GAIN_MODE(0)},
        {EMAC_SGMII_LN_UCDR_SO_CONFIG, UCDR_ENABLE | UCDR_SO_SATURATION(12)},
 
        /* TX/RX Settings */
index 9bf3b2b82e9532e2662727a31d0846447ee64b39..57b35aeac51a0e33334319f8e5567ede3fd37ba3 100644 (file)
@@ -575,6 +575,7 @@ static const struct of_device_id emac_dt_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, emac_dt_match);
 
 #if IS_ENABLED(CONFIG_ACPI)
 static const struct acpi_device_id emac_acpi_match[] = {
@@ -710,6 +711,8 @@ static int emac_probe(struct platform_device *pdev)
 err_undo_napi:
        netif_napi_del(&adpt->rx_q.napi);
 err_undo_mdiobus:
+       if (!has_acpi_companion(&pdev->dev))
+               put_device(&adpt->phydev->mdio.dev);
        mdiobus_unregister(adpt->mii_bus);
 err_undo_clocks:
        emac_clks_teardown(adpt);
@@ -729,6 +732,8 @@ static int emac_remove(struct platform_device *pdev)
 
        emac_clks_teardown(adpt);
 
+       if (!has_acpi_companion(&pdev->dev))
+               put_device(&adpt->phydev->mdio.dev);
        mdiobus_unregister(adpt->mii_bus);
        free_netdev(netdev);
 
index e55638c7505a787e501fbae2dbcb1751b92f5859..bf000d819a21a0150e5db96c5cb660b8c8fe5caf 100644 (file)
@@ -8273,7 +8273,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if ((sizeof(dma_addr_t) > 4) &&
            (use_dac == 1 || (use_dac == -1 && pci_is_pcie(pdev) &&
                              tp->mac_version >= RTL_GIGA_MAC_VER_18)) &&
-           !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+           !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+           !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
 
                /* CPlusCmd Dual Access Cycle is only needed for non-PCIe */
                if (!pci_is_pcie(pdev))
index 630536bc72f975a171bd3ae85d105b6b2ccbbbf1..d6a217874a8bc2f79fe4c255bc43feea611870a5 100644 (file)
@@ -1008,20 +1008,18 @@ static int ravb_phy_init(struct net_device *ndev)
        of_node_put(pn);
        if (!phydev) {
                netdev_err(ndev, "failed to connect PHY\n");
-               return -ENOENT;
+               err = -ENOENT;
+               goto err_deregister_fixed_link;
        }
 
        /* This driver only support 10/100Mbit speeds on Gen3
         * at this time.
         */
        if (priv->chip_id == RCAR_GEN3) {
-               int err;
-
                err = phy_set_max_speed(phydev, SPEED_100);
                if (err) {
                        netdev_err(ndev, "failed to limit PHY to 100Mbit/s\n");
-                       phy_disconnect(phydev);
-                       return err;
+                       goto err_phy_disconnect;
                }
 
                netdev_info(ndev, "limited PHY to 100Mbit/s\n");
@@ -1033,6 +1031,14 @@ static int ravb_phy_init(struct net_device *ndev)
        phy_attached_info(phydev);
 
        return 0;
+
+err_phy_disconnect:
+       phy_disconnect(phydev);
+err_deregister_fixed_link:
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
+
+       return err;
 }
 
 /* PHY control start function */
@@ -1634,6 +1640,7 @@ static void ravb_set_rx_mode(struct net_device *ndev)
 /* Device close function for Ethernet AVB */
 static int ravb_close(struct net_device *ndev)
 {
+       struct device_node *np = ndev->dev.parent->of_node;
        struct ravb_private *priv = netdev_priv(ndev);
        struct ravb_tstamp_skb *ts_skb, *ts_skb2;
 
@@ -1663,6 +1670,8 @@ static int ravb_close(struct net_device *ndev)
        if (ndev->phydev) {
                phy_stop(ndev->phydev);
                phy_disconnect(ndev->phydev);
+               if (of_phy_is_fixed_link(np))
+                       of_phy_deregister_fixed_link(np);
        }
 
        if (priv->chip_id != RCAR_GEN2) {
index 05b0dc55de774f486699e066ec24370129b42061..1a92de7051996372975278c0541e1f4c96b8858c 100644 (file)
@@ -518,7 +518,7 @@ static struct sh_eth_cpu_data r7s72100_data = {
 
        .ecsr_value     = ECSR_ICD,
        .ecsipr_value   = ECSIPR_ICDIP,
-       .eesipr_value   = 0xff7f009f,
+       .eesipr_value   = 0xe77f009f,
 
        .tx_check       = EESR_TC1 | EESR_FTC,
        .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
index 5424fb341613fe578b237f3498dc83a5237b2ede..24b746406bc7a505ee08c75ef3713a0be5e6dba7 100644 (file)
@@ -1471,7 +1471,7 @@ static int rocker_world_check_init(struct rocker_port *rocker_port)
        if (rocker->wops) {
                if (rocker->wops->mode != mode) {
                        dev_err(&rocker->pdev->dev, "hardware has ports in different worlds, which is not supported\n");
-                       return err;
+                       return -EINVAL;
                }
                return 0;
        }
index 431a608042727f7bb9cedf404a9429fa665e3143..4ca461322d6089553f05a623823f6e92cbe57455 100644 (file)
@@ -1493,8 +1493,6 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port,
        spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags);
 
        found = ofdpa_neigh_tbl_find(ofdpa, ip_addr);
-       if (found)
-               *index = found->index;
 
        updating = found && adding;
        removing = found && !adding;
@@ -1508,9 +1506,11 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port,
                resolved = false;
        } else if (removing) {
                ofdpa_neigh_del(trans, found);
+               *index = found->index;
        } else if (updating) {
                ofdpa_neigh_update(found, trans, NULL, false);
                resolved = !is_zero_ether_addr(found->eth_dst);
+               *index = found->index;
        } else {
                err = -ENOENT;
        }
index 3cf3557106c22f335ca5e04d2065e01d41056572..6b89e4a7b16467da442631df9d8bf14c48abe070 100644 (file)
@@ -485,6 +485,9 @@ efx_copy_channel(const struct efx_channel *old_channel)
        *channel = *old_channel;
 
        channel->napi_dev = NULL;
+       INIT_HLIST_NODE(&channel->napi_str.napi_hash_node);
+       channel->napi_str.napi_id = 0;
+       channel->napi_str.state = 0;
        memset(&channel->eventq, 0, sizeof(channel->eventq));
 
        for (j = 0; j < EFX_TXQ_TYPES; j++) {
index e9b8579e6241476bd2c82486a0e1a91b2cafcad7..8b0016a785c0610a28a4671e621d9e18ede72cec 100644 (file)
@@ -438,9 +438,16 @@ static int smsc911x_request_resources(struct platform_device *pdev)
        ret = regulator_bulk_get(&pdev->dev,
                        ARRAY_SIZE(pdata->supplies),
                        pdata->supplies);
-       if (ret)
+       if (ret) {
+               /*
+                * Retry on deferrals, else just report the error
+                * and try to continue.
+                */
+               if (ret == -EPROBE_DEFER)
+                       return ret;
                netdev_err(ndev, "couldn't get regulators %d\n",
                                ret);
+       }
 
        /* Request optional RESET GPIO */
        pdata->reset_gpiod = devm_gpiod_get_optional(&pdev->dev,
index 3818c5e06ebac5099f8051c813222349a2f6a6a5..4b78168a5f3ce8cd8b971c3e88c5addf1f46a7e3 100644 (file)
@@ -107,7 +107,7 @@ config DWMAC_STI
 config DWMAC_STM32
        tristate "STM32 DWMAC support"
        default ARCH_STM32
-       depends on OF && HAS_IOMEM
+       depends on OF && HAS_IOMEM && (ARCH_STM32 || COMPILE_TEST)
        select MFD_SYSCON
        ---help---
          Support for ethernet controller on STM32 SOCs.
index 2920e2ee38647095afa97653c3d4dd9901f77d23..489ef146201e61c629c17010f672a621642e94b3 100644 (file)
@@ -63,8 +63,8 @@
 #define TSE_PCS_SGMII_LINK_TIMER_0                     0x0D40
 #define TSE_PCS_SGMII_LINK_TIMER_1                     0x0003
 #define TSE_PCS_SW_RESET_TIMEOUT                       100
-#define TSE_PCS_USE_SGMII_AN_MASK                      BIT(2)
-#define TSE_PCS_USE_SGMII_ENA                          BIT(1)
+#define TSE_PCS_USE_SGMII_AN_MASK                      BIT(1)
+#define TSE_PCS_USE_SGMII_ENA                          BIT(0)
 
 #define SGMII_ADAPTER_CTRL_REG                         0x00
 #define SGMII_ADAPTER_DISABLE                          0x0001
index d3292c4a6eda3f6f9f17fecfc18e86880ebc4d61..6d2de4e01f6d00404bde51f3816ba2271adff865 100644 (file)
@@ -120,14 +120,17 @@ struct stmmac_extra_stats {
        unsigned long ip_csum_bypassed;
        unsigned long ipv4_pkt_rcvd;
        unsigned long ipv6_pkt_rcvd;
-       unsigned long rx_msg_type_ext_no_ptp;
-       unsigned long rx_msg_type_sync;
-       unsigned long rx_msg_type_follow_up;
-       unsigned long rx_msg_type_delay_req;
-       unsigned long rx_msg_type_delay_resp;
-       unsigned long rx_msg_type_pdelay_req;
-       unsigned long rx_msg_type_pdelay_resp;
-       unsigned long rx_msg_type_pdelay_follow_up;
+       unsigned long no_ptp_rx_msg_type_ext;
+       unsigned long ptp_rx_msg_type_sync;
+       unsigned long ptp_rx_msg_type_follow_up;
+       unsigned long ptp_rx_msg_type_delay_req;
+       unsigned long ptp_rx_msg_type_delay_resp;
+       unsigned long ptp_rx_msg_type_pdelay_req;
+       unsigned long ptp_rx_msg_type_pdelay_resp;
+       unsigned long ptp_rx_msg_type_pdelay_follow_up;
+       unsigned long ptp_rx_msg_type_announce;
+       unsigned long ptp_rx_msg_type_management;
+       unsigned long ptp_rx_msg_pkt_reserved_type;
        unsigned long ptp_frame_type;
        unsigned long ptp_ver;
        unsigned long timestamp_dropped;
@@ -482,11 +485,12 @@ struct stmmac_ops {
 /* PTP and HW Timer helpers */
 struct stmmac_hwtimestamp {
        void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
-       u32 (*config_sub_second_increment) (void __iomem *ioaddr, u32 clk_rate);
+       u32 (*config_sub_second_increment)(void __iomem *ioaddr, u32 ptp_clock,
+                                          int gmac4);
        int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
        int (*config_addend) (void __iomem *ioaddr, u32 addend);
        int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
-                              int add_sub);
+                              int add_sub, int gmac4);
         u64(*get_systime) (void __iomem *ioaddr);
 };
 
index 2e4c171a2b4146f6276855ab14a3ba83e85680ad..e3c86d42210953c5f4f985144a3c6eddfe6f4c73 100644 (file)
 #define        ERDES4_L3_L4_FILT_NO_MATCH_MASK GENMASK(27, 26)
 
 /* Extended RDES4 message type definitions */
-#define RDES_EXT_NO_PTP                        0
-#define RDES_EXT_SYNC                  1
-#define RDES_EXT_FOLLOW_UP             2
-#define RDES_EXT_DELAY_REQ             3
-#define RDES_EXT_DELAY_RESP            4
-#define RDES_EXT_PDELAY_REQ            5
-#define RDES_EXT_PDELAY_RESP           6
-#define RDES_EXT_PDELAY_FOLLOW_UP      7
+#define RDES_EXT_NO_PTP                        0x0
+#define RDES_EXT_SYNC                  0x1
+#define RDES_EXT_FOLLOW_UP             0x2
+#define RDES_EXT_DELAY_REQ             0x3
+#define RDES_EXT_DELAY_RESP            0x4
+#define RDES_EXT_PDELAY_REQ            0x5
+#define RDES_EXT_PDELAY_RESP           0x6
+#define RDES_EXT_PDELAY_FOLLOW_UP      0x7
+#define RDES_PTP_ANNOUNCE              0x8
+#define RDES_PTP_MANAGEMENT            0x9
+#define RDES_PTP_SIGNALING             0xa
+#define RDES_PTP_PKT_RESERVED_TYPE     0xf
 
 /* Basic descriptor structure for normal and alternate descriptors */
 struct dma_desc {
index b1e5f24708c923d5b9f4f54924bc1f8c34f64496..e6e6c2fcc4b77b7bffcc8201dc4b64bbbbdd1916 100644 (file)
@@ -50,10 +50,23 @@ static int dwmac_generic_probe(struct platform_device *pdev)
        if (plat_dat->init) {
                ret = plat_dat->init(pdev, plat_dat->bsp_priv);
                if (ret)
-                       return ret;
+                       goto err_remove_config_dt;
        }
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               goto err_exit;
+
+       return 0;
+
+err_exit:
+       if (plat_dat->exit)
+               plat_dat->exit(pdev, plat_dat->bsp_priv);
+err_remove_config_dt:
+       if (pdev->dev.of_node)
+               stmmac_remove_config_dt(pdev, plat_dat);
+
+       return ret;
 }
 
 static const struct of_device_id dwmac_generic_match[] = {
index 36d3355f2fb00e1ab12dc67813efd7ce5e473251..866444b6c82faa773b622c861bb000e544a05d7a 100644 (file)
@@ -271,15 +271,17 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
                return PTR_ERR(plat_dat);
 
        gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
-       if (!gmac)
-               return -ENOMEM;
+       if (!gmac) {
+               err = -ENOMEM;
+               goto err_remove_config_dt;
+       }
 
        gmac->pdev = pdev;
 
        err = ipq806x_gmac_of_parse(gmac);
        if (err) {
                dev_err(dev, "device tree parsing error\n");
-               return err;
+               goto err_remove_config_dt;
        }
 
        regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
@@ -300,7 +302,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
        default:
                dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
                        phy_modes(gmac->phy_mode));
-               return -EINVAL;
+               err = -EINVAL;
+               goto err_remove_config_dt;
        }
        regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
 
@@ -319,7 +322,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
        default:
                dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
                        phy_modes(gmac->phy_mode));
-               return -EINVAL;
+               err = -EINVAL;
+               goto err_remove_config_dt;
        }
        regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
 
@@ -346,7 +350,16 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
        plat_dat->bsp_priv = gmac;
        plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed;
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (err)
+               goto err_remove_config_dt;
+
+       return 0;
+
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
+
+       return err;
 }
 
 static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
index 78e9d1861896335d86ac31e5701856d9bfe8779b..3d3f43d91b98736003b050937a2b46d2062e9bf9 100644 (file)
@@ -46,7 +46,8 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
        reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
        if (IS_ERR(reg)) {
                dev_err(&pdev->dev, "syscon lookup failed\n");
-               return PTR_ERR(reg);
+               ret = PTR_ERR(reg);
+               goto err_remove_config_dt;
        }
 
        if (plat_dat->interface == PHY_INTERFACE_MODE_MII) {
@@ -55,13 +56,23 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
                ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
        } else {
                dev_err(&pdev->dev, "Only MII and RMII mode supported\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_remove_config_dt;
        }
 
        regmap_update_bits(reg, LPC18XX_CREG_CREG6,
                           LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode);
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               goto err_remove_config_dt;
+
+       return 0;
+
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
+
+       return ret;
 }
 
 static const struct of_device_id lpc18xx_dwmac_match[] = {
index 309d99536a2c617264167d878a5239b9cdb85865..7fdd1760a74c951a63282db15ab4f9ece2bc8abf 100644 (file)
@@ -64,18 +64,31 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
                return PTR_ERR(plat_dat);
 
        dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
-       if (!dwmac)
-               return -ENOMEM;
+       if (!dwmac) {
+               ret = -ENOMEM;
+               goto err_remove_config_dt;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dwmac->reg))
-               return PTR_ERR(dwmac->reg);
+       if (IS_ERR(dwmac->reg)) {
+               ret = PTR_ERR(dwmac->reg);
+               goto err_remove_config_dt;
+       }
 
        plat_dat->bsp_priv = dwmac;
        plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               goto err_remove_config_dt;
+
+       return 0;
+
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
+
+       return ret;
 }
 
 static const struct of_device_id meson6_dwmac_match[] = {
index 250e4ceafc8dca9c627aeb2a14348c692e438804..ffaed1f35efe0754749a536c563d91937dcb4302 100644 (file)
@@ -264,32 +264,48 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
                return PTR_ERR(plat_dat);
 
        dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
-       if (!dwmac)
-               return -ENOMEM;
+       if (!dwmac) {
+               ret = -ENOMEM;
+               goto err_remove_config_dt;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        dwmac->regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dwmac->regs))
-               return PTR_ERR(dwmac->regs);
+       if (IS_ERR(dwmac->regs)) {
+               ret = PTR_ERR(dwmac->regs);
+               goto err_remove_config_dt;
+       }
 
        dwmac->pdev = pdev;
        dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node);
        if (dwmac->phy_mode < 0) {
                dev_err(&pdev->dev, "missing phy-mode property\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_remove_config_dt;
        }
 
        ret = meson8b_init_clk(dwmac);
        if (ret)
-               return ret;
+               goto err_remove_config_dt;
 
        ret = meson8b_init_prg_eth(dwmac);
        if (ret)
-               return ret;
+               goto err_remove_config_dt;
 
        plat_dat->bsp_priv = dwmac;
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               goto err_clk_disable;
+
+       return 0;
+
+err_clk_disable:
+       clk_disable_unprepare(dwmac->m25_div_clk);
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
+
+       return ret;
 }
 
 static int meson8b_dwmac_remove(struct platform_device *pdev)
index 3740a4417fa0297c2631a08785dd9345e7cb0371..d80c88bd2bba812123484f9d6b14a373bc33102f 100644 (file)
@@ -981,14 +981,27 @@ static int rk_gmac_probe(struct platform_device *pdev)
        plat_dat->resume = rk_gmac_resume;
 
        plat_dat->bsp_priv = rk_gmac_setup(pdev, data);
-       if (IS_ERR(plat_dat->bsp_priv))
-               return PTR_ERR(plat_dat->bsp_priv);
+       if (IS_ERR(plat_dat->bsp_priv)) {
+               ret = PTR_ERR(plat_dat->bsp_priv);
+               goto err_remove_config_dt;
+       }
 
        ret = rk_gmac_init(pdev, plat_dat->bsp_priv);
        if (ret)
-               return ret;
+               goto err_remove_config_dt;
+
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               goto err_gmac_exit;
+
+       return 0;
+
+err_gmac_exit:
+       rk_gmac_exit(pdev, plat_dat->bsp_priv);
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       return ret;
 }
 
 static const struct of_device_id rk_gmac_dwmac_match[] = {
index bec6963ac71e978e8959fce41607e06ceb955518..0c420e97de1e6693338f0d50174d8c93a47d735c 100644 (file)
@@ -304,6 +304,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
        struct device           *dev = &pdev->dev;
        int                     ret;
        struct socfpga_dwmac    *dwmac;
+       struct net_device       *ndev;
+       struct stmmac_priv      *stpriv;
 
        ret = stmmac_get_platform_resources(pdev, &stmmac_res);
        if (ret)
@@ -314,32 +316,43 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
                return PTR_ERR(plat_dat);
 
        dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
-       if (!dwmac)
-               return -ENOMEM;
+       if (!dwmac) {
+               ret = -ENOMEM;
+               goto err_remove_config_dt;
+       }
 
        ret = socfpga_dwmac_parse_data(dwmac, dev);
        if (ret) {
                dev_err(dev, "Unable to parse OF data\n");
-               return ret;
+               goto err_remove_config_dt;
        }
 
        plat_dat->bsp_priv = dwmac;
        plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
 
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               goto err_remove_config_dt;
 
-       if (!ret) {
-               struct net_device *ndev = platform_get_drvdata(pdev);
-               struct stmmac_priv *stpriv = netdev_priv(ndev);
+       ndev = platform_get_drvdata(pdev);
+       stpriv = netdev_priv(ndev);
 
-               /* The socfpga driver needs to control the stmmac reset to
-                * set the phy mode. Create a copy of the core reset handel
-                * so it can be used by the driver later.
-                */
-               dwmac->stmmac_rst = stpriv->stmmac_rst;
+       /* The socfpga driver needs to control the stmmac reset to set the phy
+        * mode. Create a copy of the core reset handle so it can be used by
+        * the driver later.
+        */
+       dwmac->stmmac_rst = stpriv->stmmac_rst;
 
-               ret = socfpga_dwmac_set_phy_mode(dwmac);
-       }
+       ret = socfpga_dwmac_set_phy_mode(dwmac);
+       if (ret)
+               goto err_dvr_remove;
+
+       return 0;
+
+err_dvr_remove:
+       stmmac_dvr_remove(&pdev->dev);
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
 
        return ret;
 }
index 58c05acc2aabbdf63419874605ae11af298471ca..060b98c37a851834f1f1293d67795b9e31ec5a85 100644 (file)
@@ -345,13 +345,15 @@ static int sti_dwmac_probe(struct platform_device *pdev)
                return PTR_ERR(plat_dat);
 
        dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
-       if (!dwmac)
-               return -ENOMEM;
+       if (!dwmac) {
+               ret = -ENOMEM;
+               goto err_remove_config_dt;
+       }
 
        ret = sti_dwmac_parse_data(dwmac, pdev);
        if (ret) {
                dev_err(&pdev->dev, "Unable to parse OF data\n");
-               return ret;
+               goto err_remove_config_dt;
        }
 
        dwmac->fix_retime_src = data->fix_retime_src;
@@ -363,9 +365,20 @@ static int sti_dwmac_probe(struct platform_device *pdev)
 
        ret = sti_dwmac_init(pdev, plat_dat->bsp_priv);
        if (ret)
-               return ret;
+               goto err_remove_config_dt;
+
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+               goto err_dwmac_exit;
+
+       return 0;
+
+err_dwmac_exit:
+       sti_dwmac_exit(pdev, plat_dat->bsp_priv);
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
 
-       return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       return ret;
 }
 
 static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
index e5a926b8bee7274fc2bd2ce4a60525831e91dce4..61cb24810d101194c5285cf27edd963aa488473f 100644 (file)
@@ -107,24 +107,33 @@ static int stm32_dwmac_probe(struct platform_device *pdev)
                return PTR_ERR(plat_dat);
 
        dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
-       if (!dwmac)
-               return -ENOMEM;
+       if (!dwmac) {
+               ret = -ENOMEM;
+               goto err_remove_config_dt;
+       }
 
        ret = stm32_dwmac_parse_data(dwmac, &pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Unable to parse OF data\n");
-               return ret;
+               goto err_remove_config_dt;
        }
 
        plat_dat->bsp_priv = dwmac;
 
        ret = stm32_dwmac_init(plat_dat);
        if (ret)
-               return ret;
+               goto err_remove_config_dt;
 
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
        if (ret)
-               stm32_dwmac_clk_disable(dwmac);
+               goto err_clk_disable;
+
+       return 0;
+
+err_clk_disable:
+       stm32_dwmac_clk_disable(dwmac);
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
 
        return ret;
 }
index adff46375a32297ce01a7fdd519483ccc1226012..d07520fb969e687aa6ee5c384c7e23ecf3a8e38a 100644 (file)
@@ -120,22 +120,27 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
                return PTR_ERR(plat_dat);
 
        gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
-       if (!gmac)
-               return -ENOMEM;
+       if (!gmac) {
+               ret = -ENOMEM;
+               goto err_remove_config_dt;
+       }
 
        gmac->interface = of_get_phy_mode(dev->of_node);
 
        gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
        if (IS_ERR(gmac->tx_clk)) {
                dev_err(dev, "could not get tx clock\n");
-               return PTR_ERR(gmac->tx_clk);
+               ret = PTR_ERR(gmac->tx_clk);
+               goto err_remove_config_dt;
        }
 
        /* Optional regulator for PHY */
        gmac->regulator = devm_regulator_get_optional(dev, "phy");
        if (IS_ERR(gmac->regulator)) {
-               if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) {
+                       ret = -EPROBE_DEFER;
+                       goto err_remove_config_dt;
+               }
                dev_info(dev, "no regulator found\n");
                gmac->regulator = NULL;
        }
@@ -151,11 +156,18 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
 
        ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv);
        if (ret)
-               return ret;
+               goto err_remove_config_dt;
 
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
        if (ret)
-               sun7i_gmac_exit(pdev, plat_dat->bsp_priv);
+               goto err_gmac_exit;
+
+       return 0;
+
+err_gmac_exit:
+       sun7i_gmac_exit(pdev, plat_dat->bsp_priv);
+err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
 
        return ret;
 }
index 9907469552169094a2fea15812021dde40b4e8e8..f35385266fbf04d595c65b469b14c5abcd7e565c 100644 (file)
@@ -43,9 +43,11 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
        if (axi->axi_xit_frm)
                value |= DMA_AXI_LPI_XIT_FRM;
 
+       value &= ~DMA_AXI_WR_OSR_LMT;
        value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
                 DMA_AXI_WR_OSR_LMT_SHIFT;
 
+       value &= ~DMA_AXI_RD_OSR_LMT;
        value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
                 DMA_AXI_RD_OSR_LMT_SHIFT;
 
index 4ec7397e7fb378d1d82368c5fb9aff28e5340c6c..a601f8d43b75d8a97cc007ebaad4eed9ebd66ae3 100644 (file)
@@ -123,22 +123,29 @@ static int dwmac4_wrback_get_rx_status(void *data, struct stmmac_extra_stats *x,
                x->ipv4_pkt_rcvd++;
        if (rdes1 & RDES1_IPV6_HEADER)
                x->ipv6_pkt_rcvd++;
-       if (message_type == RDES_EXT_SYNC)
-               x->rx_msg_type_sync++;
+
+       if (message_type == RDES_EXT_NO_PTP)
+               x->no_ptp_rx_msg_type_ext++;
+       else if (message_type == RDES_EXT_SYNC)
+               x->ptp_rx_msg_type_sync++;
        else if (message_type == RDES_EXT_FOLLOW_UP)
-               x->rx_msg_type_follow_up++;
+               x->ptp_rx_msg_type_follow_up++;
        else if (message_type == RDES_EXT_DELAY_REQ)
-               x->rx_msg_type_delay_req++;
+               x->ptp_rx_msg_type_delay_req++;
        else if (message_type == RDES_EXT_DELAY_RESP)
-               x->rx_msg_type_delay_resp++;
+               x->ptp_rx_msg_type_delay_resp++;
        else if (message_type == RDES_EXT_PDELAY_REQ)
-               x->rx_msg_type_pdelay_req++;
+               x->ptp_rx_msg_type_pdelay_req++;
        else if (message_type == RDES_EXT_PDELAY_RESP)
-               x->rx_msg_type_pdelay_resp++;
+               x->ptp_rx_msg_type_pdelay_resp++;
        else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
-               x->rx_msg_type_pdelay_follow_up++;
-       else
-               x->rx_msg_type_ext_no_ptp++;
+               x->ptp_rx_msg_type_pdelay_follow_up++;
+       else if (message_type == RDES_PTP_ANNOUNCE)
+               x->ptp_rx_msg_type_announce++;
+       else if (message_type == RDES_PTP_MANAGEMENT)
+               x->ptp_rx_msg_type_management++;
+       else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
+               x->ptp_rx_msg_pkt_reserved_type++;
 
        if (rdes1 & RDES1_PTP_PACKET_TYPE)
                x->ptp_frame_type++;
@@ -204,14 +211,18 @@ static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p)
 
 static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p)
 {
-       return (p->des3 & TDES3_TIMESTAMP_STATUS)
-               >> TDES3_TIMESTAMP_STATUS_SHIFT;
+       /* Context type from W/B descriptor must be zero */
+       if (p->des3 & TDES3_CONTEXT_TYPE)
+               return -EINVAL;
+
+       /* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
+       if (p->des3 & TDES3_TIMESTAMP_STATUS)
+               return 0;
+
+       return 1;
 }
 
-/*  NOTE: For RX CTX bit has to be checked before
- *  HAVE a specific function for TX and another one for RX
- */
-static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
+static inline u64 dwmac4_get_timestamp(void *desc, u32 ats)
 {
        struct dma_desc *p = (struct dma_desc *)desc;
        u64 ns;
@@ -223,12 +234,54 @@ static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
        return ns;
 }
 
-static int dwmac4_context_get_rx_timestamp_status(void *desc, u32 ats)
+static int dwmac4_rx_check_timestamp(void *desc)
+{
+       struct dma_desc *p = (struct dma_desc *)desc;
+       u32 own, ctxt;
+       int ret = 1;
+
+       own = p->des3 & RDES3_OWN;
+       ctxt = ((p->des3 & RDES3_CONTEXT_DESCRIPTOR)
+               >> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
+
+       if (likely(!own && ctxt)) {
+               if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
+                       /* Corrupted value */
+                       ret = -EINVAL;
+               else
+                       /* A valid Timestamp is ready to be read */
+                       ret = 0;
+       }
+
+       /* Timestamp not ready */
+       return ret;
+}
+
+static int dwmac4_wrback_get_rx_timestamp_status(void *desc, u32 ats)
 {
        struct dma_desc *p = (struct dma_desc *)desc;
+       int ret = -EINVAL;
+
+       /* Get the status from normal w/b descriptor */
+       if (likely(p->des3 & TDES3_RS1V)) {
+               if (likely(p->des1 & RDES1_TIMESTAMP_AVAILABLE)) {
+                       int i = 0;
+
+                       /* Check if timestamp is OK from context descriptor */
+                       do {
+                               ret = dwmac4_rx_check_timestamp(desc);
+                               if (ret < 0)
+                                       goto exit;
+                               i++;
 
-       return (p->des1 & RDES1_TIMESTAMP_AVAILABLE)
-               >> RDES1_TIMESTAMP_AVAILABLE_SHIFT;
+                       } while ((ret == 1) || (i < 10));
+
+                       if (i == 10)
+                               ret = -EBUSY;
+               }
+       }
+exit:
+       return ret;
 }
 
 static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
@@ -347,10 +400,9 @@ static void dwmac4_display_ring(void *head, unsigned int size, bool rx)
        pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
 
        for (i = 0; i < size; i++) {
-               if (p->des0)
-                       pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
-                               i, (unsigned int)virt_to_phys(p),
-                               p->des0, p->des1, p->des2, p->des3);
+               pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+                       i, (unsigned int)virt_to_phys(p),
+                       p->des0, p->des1, p->des2, p->des3);
                p++;
        }
 }
@@ -374,8 +426,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
        .get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
        .enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
        .get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,
-       .get_timestamp = dwmac4_wrback_get_timestamp,
-       .get_rx_timestamp_status = dwmac4_context_get_rx_timestamp_status,
+       .get_rx_timestamp_status = dwmac4_wrback_get_rx_timestamp_status,
+       .get_timestamp = dwmac4_get_timestamp,
        .set_tx_ic = dwmac4_rd_set_tx_ic,
        .prepare_tx_desc = dwmac4_rd_prepare_tx_desc,
        .prepare_tso_tx_desc = dwmac4_rd_prepare_tso_tx_desc,
index 0902a2edeaa9414cedd370f196d6bddab0c11c3a..9736c505211add1db476c3426c701a04961f4ed4 100644 (file)
 #define TDES3_CTXT_TCMSSV              BIT(26)
 
 /* TDES3 Common */
+#define        TDES3_RS1V                      BIT(26)
+#define        TDES3_RS1V_SHIFT                26
 #define TDES3_LAST_DESCRIPTOR          BIT(28)
 #define TDES3_LAST_DESCRIPTOR_SHIFT    28
 #define TDES3_FIRST_DESCRIPTOR         BIT(29)
 #define TDES3_CONTEXT_TYPE             BIT(30)
+#define        TDES3_CONTEXT_TYPE_SHIFT        30
 
 /* TDS3 use for both format (read and write back) */
 #define TDES3_OWN                      BIT(31)
 #define RDES3_LAST_DESCRIPTOR          BIT(28)
 #define RDES3_FIRST_DESCRIPTOR         BIT(29)
 #define RDES3_CONTEXT_DESCRIPTOR       BIT(30)
+#define RDES3_CONTEXT_DESCRIPTOR_SHIFT 30
 
 /* RDES3 (read format) */
 #define RDES3_BUFFER1_VALID_ADDR       BIT(24)
index 116151cd6a952378ba8bdc297d8e2e568edabc97..32bc2fc73cdc2b7f228570bdbe4c95760c1f5cc6 100644 (file)
@@ -30,9 +30,11 @@ static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
        if (axi->axi_xit_frm)
                value |= DMA_AXI_LPI_XIT_FRM;
 
+       value &= ~DMA_AXI_WR_OSR_LMT;
        value |= (axi->axi_wr_osr_lmt & DMA_AXI_OSR_MAX) <<
                 DMA_AXI_WR_OSR_LMT_SHIFT;
 
+       value &= ~DMA_AXI_RD_OSR_LMT;
        value |= (axi->axi_rd_osr_lmt & DMA_AXI_OSR_MAX) <<
                 DMA_AXI_RD_OSR_LMT_SHIFT;
 
index 38f19c99cf59e7382cc6a72d15deb2a50f1c4b96..e75549327c3451ad5aba452d20769fd31e403c2b 100644 (file)
@@ -150,22 +150,30 @@ static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
                        x->ipv4_pkt_rcvd++;
                if (rdes4 & ERDES4_IPV6_PKT_RCVD)
                        x->ipv6_pkt_rcvd++;
-               if (message_type == RDES_EXT_SYNC)
-                       x->rx_msg_type_sync++;
+
+               if (message_type == RDES_EXT_NO_PTP)
+                       x->no_ptp_rx_msg_type_ext++;
+               else if (message_type == RDES_EXT_SYNC)
+                       x->ptp_rx_msg_type_sync++;
                else if (message_type == RDES_EXT_FOLLOW_UP)
-                       x->rx_msg_type_follow_up++;
+                       x->ptp_rx_msg_type_follow_up++;
                else if (message_type == RDES_EXT_DELAY_REQ)
-                       x->rx_msg_type_delay_req++;
+                       x->ptp_rx_msg_type_delay_req++;
                else if (message_type == RDES_EXT_DELAY_RESP)
-                       x->rx_msg_type_delay_resp++;
+                       x->ptp_rx_msg_type_delay_resp++;
                else if (message_type == RDES_EXT_PDELAY_REQ)
-                       x->rx_msg_type_pdelay_req++;
+                       x->ptp_rx_msg_type_pdelay_req++;
                else if (message_type == RDES_EXT_PDELAY_RESP)
-                       x->rx_msg_type_pdelay_resp++;
+                       x->ptp_rx_msg_type_pdelay_resp++;
                else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
-                       x->rx_msg_type_pdelay_follow_up++;
-               else
-                       x->rx_msg_type_ext_no_ptp++;
+                       x->ptp_rx_msg_type_pdelay_follow_up++;
+               else if (message_type == RDES_PTP_ANNOUNCE)
+                       x->ptp_rx_msg_type_announce++;
+               else if (message_type == RDES_PTP_MANAGEMENT)
+                       x->ptp_rx_msg_type_management++;
+               else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
+                       x->ptp_rx_msg_pkt_reserved_type++;
+
                if (rdes4 & ERDES4_PTP_FRAME_TYPE)
                        x->ptp_frame_type++;
                if (rdes4 & ERDES4_PTP_VER)
index 8dc9056c100105aecf77754128f74913bd9b1524..4d2a759b84652165d8e70e4284af744f1edb3e75 100644 (file)
@@ -129,6 +129,7 @@ struct stmmac_priv {
        int irq_wake;
        spinlock_t ptp_lock;
        void __iomem *mmcaddr;
+       void __iomem *ptpaddr;
        u32 rx_tail_addr;
        u32 tx_tail_addr;
        u32 mss;
@@ -145,7 +146,7 @@ int stmmac_mdio_register(struct net_device *ndev);
 int stmmac_mdio_reset(struct mii_bus *mii);
 void stmmac_set_ethtool_ops(struct net_device *netdev);
 
-int stmmac_ptp_register(struct stmmac_priv *priv);
+void stmmac_ptp_register(struct stmmac_priv *priv);
 void stmmac_ptp_unregister(struct stmmac_priv *priv);
 int stmmac_resume(struct device *dev);
 int stmmac_suspend(struct device *dev);
index 1e06173fc9d733d63c1e5ccbbc12c03506d0a44c..c5d0142adda2e00e958b0a851acc506769f8cdb5 100644 (file)
@@ -115,14 +115,17 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
        STMMAC_STAT(ip_csum_bypassed),
        STMMAC_STAT(ipv4_pkt_rcvd),
        STMMAC_STAT(ipv6_pkt_rcvd),
-       STMMAC_STAT(rx_msg_type_ext_no_ptp),
-       STMMAC_STAT(rx_msg_type_sync),
-       STMMAC_STAT(rx_msg_type_follow_up),
-       STMMAC_STAT(rx_msg_type_delay_req),
-       STMMAC_STAT(rx_msg_type_delay_resp),
-       STMMAC_STAT(rx_msg_type_pdelay_req),
-       STMMAC_STAT(rx_msg_type_pdelay_resp),
-       STMMAC_STAT(rx_msg_type_pdelay_follow_up),
+       STMMAC_STAT(no_ptp_rx_msg_type_ext),
+       STMMAC_STAT(ptp_rx_msg_type_sync),
+       STMMAC_STAT(ptp_rx_msg_type_follow_up),
+       STMMAC_STAT(ptp_rx_msg_type_delay_req),
+       STMMAC_STAT(ptp_rx_msg_type_delay_resp),
+       STMMAC_STAT(ptp_rx_msg_type_pdelay_req),
+       STMMAC_STAT(ptp_rx_msg_type_pdelay_resp),
+       STMMAC_STAT(ptp_rx_msg_type_pdelay_follow_up),
+       STMMAC_STAT(ptp_rx_msg_type_announce),
+       STMMAC_STAT(ptp_rx_msg_type_management),
+       STMMAC_STAT(ptp_rx_msg_pkt_reserved_type),
        STMMAC_STAT(ptp_frame_type),
        STMMAC_STAT(ptp_ver),
        STMMAC_STAT(timestamp_dropped),
index a77f68918010d3a511c4a97cd3b2c83671f9f542..10d6059b2f26555af9963812f847b68109b9c959 100644 (file)
@@ -34,21 +34,29 @@ static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
 }
 
 static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr,
-                                             u32 ptp_clock)
+                                             u32 ptp_clock, int gmac4)
 {
        u32 value = readl(ioaddr + PTP_TCR);
        unsigned long data;
 
-       /* Convert the ptp_clock to nano second
-        * formula = (2/ptp_clock) * 1000000000
-        * where, ptp_clock = 50MHz.
+       /* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second
+        *      formula = (1/ptp_clock) * 1000000000
+        * where ptp_clock is 50MHz if fine method is used to update system
         */
-       data = (2000000000ULL / ptp_clock);
+       if (value & PTP_TCR_TSCFUPDT)
+               data = (1000000000ULL / 50000000);
+       else
+               data = (1000000000ULL / ptp_clock);
 
        /* 0.465ns accuracy */
        if (!(value & PTP_TCR_TSCTRLSSR))
                data = (data * 1000) / 465;
 
+       data &= PTP_SSIR_SSINC_MASK;
+
+       if (gmac4)
+               data = data << GMAC4_PTP_SSIR_SSINC_SHIFT;
+
        writel(data, ioaddr + PTP_SSIR);
 
        return data;
@@ -104,14 +112,30 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
 }
 
 static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
-                                int add_sub)
+                                int add_sub, int gmac4)
 {
        u32 value;
        int limit;
 
+       if (add_sub) {
+               /* If the new sec value needs to be subtracted with
+                * the system time, then MAC_STSUR reg should be
+                * programmed with (2^32 â€“ <new_sec_value>)
+                */
+               if (gmac4)
+                       sec = (100000000ULL - sec);
+
+               value = readl(ioaddr + PTP_TCR);
+               if (value & PTP_TCR_TSCTRLSSR)
+                       nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
+               else
+                       nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
+       }
+
        writel(sec, ioaddr + PTP_STSUR);
-       writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
-               ioaddr + PTP_STNSUR);
+       value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
+       writel(value, ioaddr + PTP_STNSUR);
+
        /* issue command to initialize the system time value */
        value = readl(ioaddr + PTP_TCR);
        value |= PTP_TCR_TSUPDT;
@@ -134,8 +158,9 @@ static u64 stmmac_get_systime(void __iomem *ioaddr)
 {
        u64 ns;
 
+       /* Get the TSSS value */
        ns = readl(ioaddr + PTP_STNSR);
-       /* convert sec time value to nanosecond */
+       /* Get the TSS and convert sec time value to nanosecond */
        ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
 
        return ns;
index 6c85b61aaa0bcd94230cb1766d3558a33808738e..caf069a465f234121315cc39f5f38007791a57ec 100644 (file)
@@ -340,18 +340,17 @@ out:
 
 /* stmmac_get_tx_hwtstamp - get HW TX timestamps
  * @priv: driver private structure
- * @entry : descriptor index to be used.
+ * @p : descriptor pointer
  * @skb : the socket buffer
  * Description :
  * This function will read timestamp from the descriptor & pass it to stack.
  * and also perform some sanity checks.
  */
 static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
-                                  unsigned int entry, struct sk_buff *skb)
+                                  struct dma_desc *p, struct sk_buff *skb)
 {
        struct skb_shared_hwtstamps shhwtstamp;
        u64 ns;
-       void *desc = NULL;
 
        if (!priv->hwts_tx_en)
                return;
@@ -360,58 +359,55 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
        if (likely(!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
                return;
 
-       if (priv->adv_ts)
-               desc = (priv->dma_etx + entry);
-       else
-               desc = (priv->dma_tx + entry);
-
        /* check tx tstamp status */
-       if (!priv->hw->desc->get_tx_timestamp_status((struct dma_desc *)desc))
-               return;
+       if (!priv->hw->desc->get_tx_timestamp_status(p)) {
+               /* get the valid tstamp */
+               ns = priv->hw->desc->get_timestamp(p, priv->adv_ts);
 
-       /* get the valid tstamp */
-       ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
+               memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+               shhwtstamp.hwtstamp = ns_to_ktime(ns);
 
-       memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
-       shhwtstamp.hwtstamp = ns_to_ktime(ns);
-       /* pass tstamp to stack */
-       skb_tstamp_tx(skb, &shhwtstamp);
+               netdev_info(priv->dev, "get valid TX hw timestamp %llu\n", ns);
+               /* pass tstamp to stack */
+               skb_tstamp_tx(skb, &shhwtstamp);
+       }
 
        return;
 }
 
 /* stmmac_get_rx_hwtstamp - get HW RX timestamps
  * @priv: driver private structure
- * @entry : descriptor index to be used.
+ * @p : descriptor pointer
+ * @np : next descriptor pointer
  * @skb : the socket buffer
  * Description :
  * This function will read received packet's timestamp from the descriptor
  * and pass it to stack. It also perform some sanity checks.
  */
-static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv,
-                                  unsigned int entry, struct sk_buff *skb)
+static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
+                                  struct dma_desc *np, struct sk_buff *skb)
 {
        struct skb_shared_hwtstamps *shhwtstamp = NULL;
        u64 ns;
-       void *desc = NULL;
 
        if (!priv->hwts_rx_en)
                return;
 
-       if (priv->adv_ts)
-               desc = (priv->dma_erx + entry);
-       else
-               desc = (priv->dma_rx + entry);
-
-       /* exit if rx tstamp is not valid */
-       if (!priv->hw->desc->get_rx_timestamp_status(desc, priv->adv_ts))
-               return;
+       /* Check if timestamp is available */
+       if (!priv->hw->desc->get_rx_timestamp_status(p, priv->adv_ts)) {
+               /* For GMAC4, the valid timestamp is from CTX next desc. */
+               if (priv->plat->has_gmac4)
+                       ns = priv->hw->desc->get_timestamp(np, priv->adv_ts);
+               else
+                       ns = priv->hw->desc->get_timestamp(p, priv->adv_ts);
 
-       /* get valid tstamp */
-       ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
-       shhwtstamp = skb_hwtstamps(skb);
-       memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
-       shhwtstamp->hwtstamp = ns_to_ktime(ns);
+               netdev_info(priv->dev, "get valid RX hw timestamp %llu\n", ns);
+               shhwtstamp = skb_hwtstamps(skb);
+               memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+               shhwtstamp->hwtstamp = ns_to_ktime(ns);
+       } else  {
+               netdev_err(priv->dev, "cannot get RX hw timestamp\n");
+       }
 }
 
 /**
@@ -598,17 +594,18 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
        priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON;
 
        if (!priv->hwts_tx_en && !priv->hwts_rx_en)
-               priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
+               priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, 0);
        else {
                value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR |
                         tstamp_all | ptp_v2 | ptp_over_ethernet |
                         ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
                         ts_master_en | snap_type_sel);
-               priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value);
+               priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, value);
 
                /* program Sub Second Increment reg */
                sec_inc = priv->hw->ptp->config_sub_second_increment(
-                       priv->ioaddr, priv->clk_ptp_rate);
+                       priv->ptpaddr, priv->clk_ptp_rate,
+                       priv->plat->has_gmac4);
                temp = div_u64(1000000000ULL, sec_inc);
 
                /* calculate default added value:
@@ -618,14 +615,14 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
                 */
                temp = (u64)(temp << 32);
                priv->default_addend = div_u64(temp, priv->clk_ptp_rate);
-               priv->hw->ptp->config_addend(priv->ioaddr,
+               priv->hw->ptp->config_addend(priv->ptpaddr,
                                             priv->default_addend);
 
                /* initialize system time */
                ktime_get_real_ts64(&now);
 
                /* lower 32 bits of tv_sec are safe until y2106 */
-               priv->hw->ptp->init_systime(priv->ioaddr, (u32)now.tv_sec,
+               priv->hw->ptp->init_systime(priv->ptpaddr, (u32)now.tv_sec,
                                            now.tv_nsec);
        }
 
@@ -676,7 +673,9 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
        priv->hwts_tx_en = 0;
        priv->hwts_rx_en = 0;
 
-       return stmmac_ptp_register(priv);
+       stmmac_ptp_register(priv);
+
+       return 0;
 }
 
 static void stmmac_release_ptp(struct stmmac_priv *priv)
@@ -878,6 +877,13 @@ static int stmmac_init_phy(struct net_device *dev)
                return -ENODEV;
        }
 
+       /* stmmac_adjust_link will change this to PHY_IGNORE_INTERRUPT to avoid
+        * subsequent PHY polling, make sure we force a link transition if
+        * we have a UP/DOWN/UP transition
+        */
+       if (phydev->is_pseudo_fixed_link)
+               phydev->irq = PHY_POLL;
+
        pr_debug("stmmac_init_phy:  %s: attached to PHY (UID 0x%x)"
                 " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
 
@@ -1331,7 +1337,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
                                priv->dev->stats.tx_packets++;
                                priv->xstats.tx_pkt_n++;
                        }
-                       stmmac_get_tx_hwtstamp(priv, entry, skb);
+                       stmmac_get_tx_hwtstamp(priv, p, skb);
                }
 
                if (likely(priv->tx_skbuff_dma[entry].buf)) {
@@ -1477,10 +1483,13 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
        unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
                            MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
 
-       if (priv->synopsys_id >= DWMAC_CORE_4_00)
+       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
+               priv->ptpaddr = priv->ioaddr + PTP_GMAC4_OFFSET;
                priv->mmcaddr = priv->ioaddr + MMC_GMAC4_OFFSET;
-       else
+       } else {
+               priv->ptpaddr = priv->ioaddr + PTP_GMAC3_X_OFFSET;
                priv->mmcaddr = priv->ioaddr + MMC_GMAC3_X_OFFSET;
+       }
 
        dwmac_mmc_intr_all_mask(priv->mmcaddr);
 
@@ -1710,7 +1719,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
        if (init_ptp) {
                ret = stmmac_init_ptp(priv);
                if (ret)
-                       netdev_warn(priv->dev, "PTP support cannot init.\n");
+                       netdev_warn(priv->dev, "fail to init PTP.\n");
        }
 
 #ifdef CONFIG_DEBUG_FS
@@ -2475,7 +2484,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
        if (netif_msg_rx_status(priv)) {
                void *rx_head;
 
-               pr_debug("%s: descriptor ring:\n", __func__);
+               pr_info(">>>>>> %s: descriptor ring:\n", __func__);
                if (priv->extend_desc)
                        rx_head = (void *)priv->dma_erx;
                else
@@ -2486,6 +2495,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
        while (count < limit) {
                int status;
                struct dma_desc *p;
+               struct dma_desc *np;
 
                if (priv->extend_desc)
                        p = (struct dma_desc *)(priv->dma_erx + entry);
@@ -2505,9 +2515,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
                next_entry = priv->cur_rx;
 
                if (priv->extend_desc)
-                       prefetch(priv->dma_erx + next_entry);
+                       np = (struct dma_desc *)(priv->dma_erx + next_entry);
                else
-                       prefetch(priv->dma_rx + next_entry);
+                       np = priv->dma_rx + next_entry;
+
+               prefetch(np);
 
                if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status))
                        priv->hw->desc->rx_extended_status(&priv->dev->stats,
@@ -2559,7 +2571,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
                                frame_len -= ETH_FCS_LEN;
 
                        if (netif_msg_rx_status(priv)) {
-                               pr_debug("\tdesc: %p [entry %d] buff=0x%x\n",
+                               pr_info("\tdesc: %p [entry %d] buff=0x%x\n",
                                        p, entry, des);
                                if (frame_len > ETH_FRAME_LEN)
                                        pr_debug("\tframe size %d, COE: %d\n",
@@ -2616,13 +2628,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
                                                 DMA_FROM_DEVICE);
                        }
 
-                       stmmac_get_rx_hwtstamp(priv, entry, skb);
-
                        if (netif_msg_pktdata(priv)) {
                                pr_debug("frame received (%dbytes)", frame_len);
                                print_pkt(skb->data, frame_len);
                        }
 
+                       stmmac_get_rx_hwtstamp(priv, p, np, skb);
+
                        stmmac_rx_vlan(priv->dev, skb);
 
                        skb->protocol = eth_type_trans(skb, priv->dev);
@@ -3404,7 +3416,6 @@ int stmmac_dvr_remove(struct device *dev)
        stmmac_set_mac(priv->ioaddr, false);
        netif_carrier_off(ndev);
        unregister_netdev(ndev);
-       of_node_put(priv->plat->phy_node);
        if (priv->stmmac_rst)
                reset_control_assert(priv->stmmac_rst);
        clk_disable_unprepare(priv->pclk);
index 0a0d6a86f3979d260e2cda42282503e0d50e59ec..ac3d39c69509a72fbe1e094e79f44cf796c93457 100644 (file)
@@ -126,8 +126,10 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
        axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
        axi->axi_rb =  of_property_read_bool(np, "snps,axi_rb");
 
-       of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt);
-       of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt);
+       if (of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt))
+               axi->axi_wr_osr_lmt = 1;
+       if (of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt))
+               axi->axi_rd_osr_lmt = 1;
        of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
        of_node_put(np);
 
@@ -200,7 +202,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
 /**
  * stmmac_probe_config_dt - parse device-tree driver parameters
  * @pdev: platform_device structure
- * @plat: driver data platform structure
  * @mac: MAC address to use
  * Description:
  * this function is to read the driver parameters from device-tree and
@@ -306,7 +307,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
                                       GFP_KERNEL);
                if (!dma_cfg) {
-                       of_node_put(plat->phy_node);
+                       stmmac_remove_config_dt(pdev, plat);
                        return ERR_PTR(-ENOMEM);
                }
                plat->dma_cfg = dma_cfg;
@@ -329,14 +330,37 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
 
        return plat;
 }
+
+/**
+ * stmmac_remove_config_dt - undo the effects of stmmac_probe_config_dt()
+ * @pdev: platform_device structure
+ * @plat: driver data platform structure
+ *
+ * Release resources claimed by stmmac_probe_config_dt().
+ */
+void stmmac_remove_config_dt(struct platform_device *pdev,
+                            struct plat_stmmacenet_data *plat)
+{
+       struct device_node *np = pdev->dev.of_node;
+
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
+       of_node_put(plat->phy_node);
+}
 #else
 struct plat_stmmacenet_data *
 stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
 {
        return ERR_PTR(-ENOSYS);
 }
+
+void stmmac_remove_config_dt(struct platform_device *pdev,
+                            struct plat_stmmacenet_data *plat)
+{
+}
 #endif /* CONFIG_OF */
 EXPORT_SYMBOL_GPL(stmmac_probe_config_dt);
+EXPORT_SYMBOL_GPL(stmmac_remove_config_dt);
 
 int stmmac_get_platform_resources(struct platform_device *pdev,
                                  struct stmmac_resources *stmmac_res)
@@ -392,10 +416,13 @@ int stmmac_pltfr_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct stmmac_priv *priv = netdev_priv(ndev);
+       struct plat_stmmacenet_data *plat = priv->plat;
        int ret = stmmac_dvr_remove(&pdev->dev);
 
-       if (priv->plat->exit)
-               priv->plat->exit(pdev, priv->plat->bsp_priv);
+       if (plat->exit)
+               plat->exit(pdev, plat->bsp_priv);
+
+       stmmac_remove_config_dt(pdev, plat);
 
        return ret;
 }
index 64e147f53a9c0cae24a497ea127859580ebde3ad..b72eb0de57b70199c25213ee1b93da856cac22c2 100644 (file)
@@ -23,6 +23,8 @@
 
 struct plat_stmmacenet_data *
 stmmac_probe_config_dt(struct platform_device *pdev, const char **mac);
+void stmmac_remove_config_dt(struct platform_device *pdev,
+                            struct plat_stmmacenet_data *plat);
 
 int stmmac_get_platform_resources(struct platform_device *pdev,
                                  struct stmmac_resources *stmmac_res);
index 289d52725a6c172dc70a6f2db1255afc7161b2cd..3eb281d1db08a94ff76a3d3d21df367966a036d6 100644 (file)
@@ -54,7 +54,7 @@ static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
 
        spin_lock_irqsave(&priv->ptp_lock, flags);
 
-       priv->hw->ptp->config_addend(priv->ioaddr, addend);
+       priv->hw->ptp->config_addend(priv->ptpaddr, addend);
 
        spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
@@ -89,7 +89,8 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
 
        spin_lock_irqsave(&priv->ptp_lock, flags);
 
-       priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
+       priv->hw->ptp->adjust_systime(priv->ptpaddr, sec, nsec, neg_adj,
+                                     priv->plat->has_gmac4);
 
        spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
@@ -114,7 +115,7 @@ static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts)
 
        spin_lock_irqsave(&priv->ptp_lock, flags);
 
-       ns = priv->hw->ptp->get_systime(priv->ioaddr);
+       ns = priv->hw->ptp->get_systime(priv->ptpaddr);
 
        spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
@@ -141,7 +142,7 @@ static int stmmac_set_time(struct ptp_clock_info *ptp,
 
        spin_lock_irqsave(&priv->ptp_lock, flags);
 
-       priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
+       priv->hw->ptp->init_systime(priv->ptpaddr, ts->tv_sec, ts->tv_nsec);
 
        spin_unlock_irqrestore(&priv->ptp_lock, flags);
 
@@ -177,7 +178,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
  * Description: this function will register the ptp clock driver
  * to kernel. It also does some house keeping work.
  */
-int stmmac_ptp_register(struct stmmac_priv *priv)
+void stmmac_ptp_register(struct stmmac_priv *priv)
 {
        spin_lock_init(&priv->ptp_lock);
        priv->ptp_clock_ops = stmmac_ptp_clock_ops;
@@ -185,15 +186,10 @@ int stmmac_ptp_register(struct stmmac_priv *priv)
        priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
                                             priv->device);
        if (IS_ERR(priv->ptp_clock)) {
+               netdev_err(priv->dev, "ptp_clock_register failed\n");
                priv->ptp_clock = NULL;
-               return PTR_ERR(priv->ptp_clock);
-       }
-
-       spin_lock_init(&priv->ptp_lock);
-
-       netdev_dbg(priv->dev, "Added PTP HW clock successfully\n");
-
-       return 0;
+       } else if (priv->ptp_clock)
+               netdev_info(priv->dev, "registered PTP clock\n");
 }
 
 /**
index 4535df37c22767824d1f7bbe6db56a8e3d0644ab..c06938c47af5549658c19e9c64a568595d80510a 100644 (file)
   Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
 ******************************************************************************/
 
-#ifndef __STMMAC_PTP_H__
-#define __STMMAC_PTP_H__
+#ifndef        __STMMAC_PTP_H__
+#define        __STMMAC_PTP_H__
 
-/* IEEE 1588 PTP register offsets */
-#define PTP_TCR                0x0700  /* Timestamp Control Reg */
-#define PTP_SSIR       0x0704  /* Sub-Second Increment Reg */
-#define PTP_STSR       0x0708  /* System Time â€“ Seconds Regr */
-#define PTP_STNSR      0x070C  /* System Time â€“ Nanoseconds Reg */
-#define PTP_STSUR      0x0710  /* System Time â€“ Seconds Update Reg */
-#define PTP_STNSUR     0x0714  /* System Time â€“ Nanoseconds Update Reg */
-#define PTP_TAR                0x0718  /* Timestamp Addend Reg */
-#define PTP_TTSR       0x071C  /* Target Time Seconds Reg */
-#define PTP_TTNSR      0x0720  /* Target Time Nanoseconds Reg */
-#define        PTP_STHWSR      0x0724  /* System Time - Higher Word Seconds Reg */
-#define PTP_TSR                0x0728  /* Timestamp Status */
+#define        PTP_GMAC4_OFFSET        0xb00
+#define        PTP_GMAC3_X_OFFSET      0x700
 
-#define PTP_STNSUR_ADDSUB_SHIFT 31
+/* IEEE 1588 PTP register offsets */
+#define        PTP_TCR         0x00    /* Timestamp Control Reg */
+#define        PTP_SSIR        0x04    /* Sub-Second Increment Reg */
+#define        PTP_STSR        0x08    /* System Time â€“ Seconds Regr */
+#define        PTP_STNSR       0x0c    /* System Time â€“ Nanoseconds Reg */
+#define        PTP_STSUR       0x10    /* System Time â€“ Seconds Update Reg */
+#define        PTP_STNSUR      0x14    /* System Time â€“ Nanoseconds Update Reg */
+#define        PTP_TAR         0x18    /* Timestamp Addend Reg */
 
-/* PTP TCR defines */
-#define PTP_TCR_TSENA          0x00000001 /* Timestamp Enable */
-#define PTP_TCR_TSCFUPDT       0x00000002 /* Timestamp Fine/Coarse Update */
-#define PTP_TCR_TSINIT         0x00000004 /* Timestamp Initialize */
-#define PTP_TCR_TSUPDT         0x00000008 /* Timestamp Update */
-/* Timestamp Interrupt Trigger Enable */
-#define PTP_TCR_TSTRIG         0x00000010
-#define PTP_TCR_TSADDREG       0x00000020 /* Addend Reg Update */
-#define PTP_TCR_TSENALL                0x00000100 /* Enable Timestamp for All Frames */
-/* Timestamp Digital or Binary Rollover Control */
-#define PTP_TCR_TSCTRLSSR      0x00000200
+#define        PTP_STNSUR_ADDSUB_SHIFT 31
+#define        PTP_DIGITAL_ROLLOVER_MODE       0x3B9ACA00      /* 10e9-1 ns */
+#define        PTP_BINARY_ROLLOVER_MODE        0x80000000      /* ~0.466 ns */
 
+/* PTP Timestamp control register defines */
+#define        PTP_TCR_TSENA           BIT(0)  /* Timestamp Enable */
+#define        PTP_TCR_TSCFUPDT        BIT(1)  /* Timestamp Fine/Coarse Update */
+#define        PTP_TCR_TSINIT          BIT(2)  /* Timestamp Initialize */
+#define        PTP_TCR_TSUPDT          BIT(3)  /* Timestamp Update */
+#define        PTP_TCR_TSTRIG          BIT(4)  /* Timestamp Interrupt Trigger Enable */
+#define        PTP_TCR_TSADDREG        BIT(5)  /* Addend Reg Update */
+#define        PTP_TCR_TSENALL         BIT(8)  /* Enable Timestamp for All Frames */
+#define        PTP_TCR_TSCTRLSSR       BIT(9)  /* Digital or Binary Rollover Control */
 /* Enable PTP packet Processing for Version 2 Format */
-#define PTP_TCR_TSVER2ENA      0x00000400
+#define        PTP_TCR_TSVER2ENA       BIT(10)
 /* Enable Processing of PTP over Ethernet Frames */
-#define PTP_TCR_TSIPENA                0x00000800
+#define        PTP_TCR_TSIPENA         BIT(11)
 /* Enable Processing of PTP Frames Sent over IPv6-UDP */
-#define PTP_TCR_TSIPV6ENA      0x00001000
+#define        PTP_TCR_TSIPV6ENA       BIT(12)
 /* Enable Processing of PTP Frames Sent over IPv4-UDP */
-#define PTP_TCR_TSIPV4ENA      0x00002000
+#define        PTP_TCR_TSIPV4ENA       BIT(13)
 /* Enable Timestamp Snapshot for Event Messages */
-#define PTP_TCR_TSEVNTENA      0x00004000
+#define        PTP_TCR_TSEVNTENA       BIT(14)
 /* Enable Snapshot for Messages Relevant to Master */
-#define PTP_TCR_TSMSTRENA      0x00008000
+#define        PTP_TCR_TSMSTRENA       BIT(15)
 /* Select PTP packets for Taking Snapshots */
-#define PTP_TCR_SNAPTYPSEL_1   0x00010000
+#define        PTP_TCR_SNAPTYPSEL_1    GENMASK(17, 16)
 /* Enable MAC address for PTP Frame Filtering */
-#define PTP_TCR_TSENMACADDR    0x00040000
+#define        PTP_TCR_TSENMACADDR     BIT(18)
+
+/* SSIR defines */
+#define        PTP_SSIR_SSINC_MASK             0xff
+#define        GMAC4_PTP_SSIR_SSINC_SHIFT      16
 
-#endif /* __STMMAC_PTP_H__ */
+#endif /* __STMMAC_PTP_H__ */
index aa4f9d2d8fa98f2b5c4a63710c24ad5387f5a73f..02f452730d52ae26fedc12240311f2467dfd942b 100644 (file)
@@ -623,6 +623,7 @@ static int bigmac_init_hw(struct bigmac *bp, int from_irq)
        void __iomem *gregs        = bp->gregs;
        void __iomem *cregs        = bp->creg;
        void __iomem *bregs        = bp->bregs;
+       __u32 bblk_dvma = (__u32)bp->bblock_dvma;
        unsigned char *e = &bp->dev->dev_addr[0];
 
        /* Latch current counters into statistics. */
@@ -671,9 +672,9 @@ static int bigmac_init_hw(struct bigmac *bp, int from_irq)
                    bregs + BMAC_XIFCFG);
 
        /* Tell the QEC where the ring descriptors are. */
-       sbus_writel(bp->bblock_dvma + bib_offset(be_rxd, 0),
+       sbus_writel(bblk_dvma + bib_offset(be_rxd, 0),
                    cregs + CREG_RXDS);
-       sbus_writel(bp->bblock_dvma + bib_offset(be_txd, 0),
+       sbus_writel(bblk_dvma + bib_offset(be_txd, 0),
                    cregs + CREG_TXDS);
 
        /* Setup the FIFO pointers into QEC local memory. */
index 06dd21707353594b2150ec8afac12c440232160d..532fc56830cf319b3067b3caa6c8149f1ac115d6 100644 (file)
@@ -291,7 +291,7 @@ struct bigmac {
        void __iomem    *bregs; /* BigMAC Registers                   */
        void __iomem    *tregs; /* BigMAC Transceiver                 */
        struct bmac_init_block  *bmac_block;    /* RX and TX descriptors */
-       __u32                    bblock_dvma;   /* RX and TX descriptors */
+       dma_addr_t              bblock_dvma;    /* RX and TX descriptors */
 
        spinlock_t              lock;
 
index 9b825780b3be02829b54799b0e287ed2c8976a09..9582948145c172826d5321274b59ae7a653b1132 100644 (file)
@@ -124,7 +124,7 @@ static void qe_init_rings(struct sunqe *qep)
 {
        struct qe_init_block *qb = qep->qe_block;
        struct sunqe_buffers *qbufs = qep->buffers;
-       __u32 qbufs_dvma = qep->buffers_dvma;
+       __u32 qbufs_dvma = (__u32)qep->buffers_dvma;
        int i;
 
        qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0;
@@ -144,6 +144,7 @@ static int qe_init(struct sunqe *qep, int from_irq)
        void __iomem *mregs = qep->mregs;
        void __iomem *gregs = qecp->gregs;
        unsigned char *e = &qep->dev->dev_addr[0];
+       __u32 qblk_dvma = (__u32)qep->qblock_dvma;
        u32 tmp;
        int i;
 
@@ -152,8 +153,8 @@ static int qe_init(struct sunqe *qep, int from_irq)
                return -EAGAIN;
 
        /* Setup initial rx/tx init block pointers. */
-       sbus_writel(qep->qblock_dvma + qib_offset(qe_rxd, 0), cregs + CREG_RXDS);
-       sbus_writel(qep->qblock_dvma + qib_offset(qe_txd, 0), cregs + CREG_TXDS);
+       sbus_writel(qblk_dvma + qib_offset(qe_rxd, 0), cregs + CREG_RXDS);
+       sbus_writel(qblk_dvma + qib_offset(qe_txd, 0), cregs + CREG_TXDS);
 
        /* Enable/mask the various irq's. */
        sbus_writel(0, cregs + CREG_RIMASK);
@@ -413,7 +414,7 @@ static void qe_rx(struct sunqe *qep)
        struct net_device *dev = qep->dev;
        struct qe_rxd *this;
        struct sunqe_buffers *qbufs = qep->buffers;
-       __u32 qbufs_dvma = qep->buffers_dvma;
+       __u32 qbufs_dvma = (__u32)qep->buffers_dvma;
        int elem = qep->rx_new;
        u32 flags;
 
@@ -572,7 +573,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct sunqe *qep = netdev_priv(dev);
        struct sunqe_buffers *qbufs = qep->buffers;
-       __u32 txbuf_dvma, qbufs_dvma = qep->buffers_dvma;
+       __u32 txbuf_dvma, qbufs_dvma = (__u32)qep->buffers_dvma;
        unsigned char *txbuf;
        int len, entry;
 
index 581781b6b2fac9d6bfb4bfae9735d674f6d46eec..ae190b77431b14b8f63b465155e9762727ccad77 100644 (file)
@@ -334,12 +334,12 @@ struct sunqe {
        void __iomem                    *qcregs;                /* QEC per-channel Registers   */
        void __iomem                    *mregs;         /* Per-channel MACE Registers  */
        struct qe_init_block            *qe_block;      /* RX and TX descriptors       */
-       __u32                           qblock_dvma;    /* RX and TX descriptors       */
+       dma_addr_t                      qblock_dvma;    /* RX and TX descriptors       */
        spinlock_t                      lock;           /* Protects txfull state       */
        int                             rx_new, rx_old; /* RX ring extents             */
        int                             tx_new, tx_old; /* TX ring extents             */
        struct sunqe_buffers            *buffers;       /* CPU visible address.        */
-       __u32                           buffers_dvma;   /* DVMA visible address.       */
+       dma_addr_t                      buffers_dvma;   /* DVMA visible address.       */
        struct sunqec                   *parent;
        u8                              mconfig;        /* Base MACE mconfig value     */
        struct platform_device          *op;            /* QE's OF device struct       */
index 0d005312854255bf0e7de592f43b52bb8d8fdea3..97d64bfed465cff42fd463f0d299d2f3e5b7c401 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/stat.h>
 #include <linux/types.h>
 
-#include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
@@ -43,7 +42,6 @@
 
 #include <linux/phy.h>
 #include <linux/mii.h>
-#include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
 
@@ -982,11 +980,13 @@ static int dwceqos_mii_probe(struct net_device *ndev)
        if (netif_msg_probe(lp))
                phy_attached_info(phydev);
 
-       phydev->supported &= PHY_GBIT_FEATURES;
+       phydev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
+                            SUPPORTED_Asym_Pause;
 
        lp->link    = 0;
        lp->speed   = 0;
        lp->duplex  = DUPLEX_UNKNOWN;
+       lp->flowcontrol.autoneg = AUTONEG_ENABLE;
 
        return 0;
 }
@@ -2881,7 +2881,7 @@ static int dwceqos_probe(struct platform_device *pdev)
        ret = of_get_phy_mode(lp->pdev->dev.of_node);
        if (ret < 0) {
                dev_err(&lp->pdev->dev, "error in getting phy i/f\n");
-               goto err_out_clk_dis_phy;
+               goto err_out_deregister_fixed_link;
        }
 
        lp->phy_interface = ret;
@@ -2889,14 +2889,14 @@ static int dwceqos_probe(struct platform_device *pdev)
        ret = dwceqos_mii_init(lp);
        if (ret) {
                dev_err(&lp->pdev->dev, "error in dwceqos_mii_init\n");
-               goto err_out_clk_dis_phy;
+               goto err_out_deregister_fixed_link;
        }
 
        ret = dwceqos_mii_probe(ndev);
        if (ret != 0) {
                netdev_err(ndev, "mii_probe fail.\n");
                ret = -ENXIO;
-               goto err_out_clk_dis_phy;
+               goto err_out_deregister_fixed_link;
        }
 
        dwceqos_set_umac_addr(lp, lp->ndev->dev_addr, 0);
@@ -2914,7 +2914,7 @@ static int dwceqos_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&lp->pdev->dev, "Unable to retrieve DT, error %d\n",
                        ret);
-               goto err_out_clk_dis_phy;
+               goto err_out_deregister_fixed_link;
        }
        dev_info(&lp->pdev->dev, "pdev->id %d, baseaddr 0x%08lx, irq %d\n",
                 pdev->id, ndev->base_addr, ndev->irq);
@@ -2924,7 +2924,7 @@ static int dwceqos_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&lp->pdev->dev, "Unable to request IRQ %d, error %d\n",
                        ndev->irq, ret);
-               goto err_out_clk_dis_phy;
+               goto err_out_deregister_fixed_link;
        }
 
        if (netif_msg_probe(lp))
@@ -2935,11 +2935,14 @@ static int dwceqos_probe(struct platform_device *pdev)
        ret = register_netdev(ndev);
        if (ret) {
                dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
-                       goto err_out_clk_dis_phy;
+               goto err_out_deregister_fixed_link;
        }
 
        return 0;
 
+err_out_deregister_fixed_link:
+       if (of_phy_is_fixed_link(pdev->dev.of_node))
+               of_phy_deregister_fixed_link(pdev->dev.of_node);
 err_out_clk_dis_phy:
        clk_disable_unprepare(lp->phy_ref_clk);
 err_out_clk_dis_aper:
@@ -2959,8 +2962,11 @@ static int dwceqos_remove(struct platform_device *pdev)
        if (ndev) {
                lp = netdev_priv(ndev);
 
-               if (ndev->phydev)
+               if (ndev->phydev) {
                        phy_disconnect(ndev->phydev);
+                       if (of_phy_is_fixed_link(pdev->dev.of_node))
+                               of_phy_deregister_fixed_link(pdev->dev.of_node);
+               }
                mdiobus_unregister(lp->mii_bus);
                mdiobus_free(lp->mii_bus);
 
index fa0cfda24fd9caaf44d47812d5b1b13a2af73dcf..28097be2ff28340e2010bda5967e9edab8fdc963 100644 (file)
@@ -1113,6 +1113,7 @@ static int cpmac_probe(struct platform_device *pdev)
        if (!dev)
                return -ENOMEM;
 
+       SET_NETDEV_DEV(dev, &pdev->dev);
        platform_set_drvdata(pdev, dev);
        priv = netdev_priv(dev);
 
index 054a8dd23dae0df966fc508064734946ed8f6d2b..18013645e76c8be4a460e50d7edd31abda29900f 100644 (file)
@@ -81,6 +81,7 @@ static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,
        };
 
        mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6);
+       mask |= BIT(slave + 4);
        mode <<= slave * 2;
 
        if (priv->rmii_clock_external) {
@@ -176,9 +177,12 @@ void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave)
        }
 
        dev = bus_find_device(&platform_bus_type, NULL, node, match);
+       of_node_put(node);
        priv = dev_get_drvdata(dev);
 
        priv->cpsw_phy_sel(priv, phy_mode, slave);
+
+       put_device(dev);
 }
 EXPORT_SYMBOL_GPL(cpsw_phy_sel);
 
index c6cff3d2ff050c33c65416a1c8e6c06c44358936..b9087b828eff6183b73ba6dfe8c92ec55655b1a9 100644 (file)
@@ -2375,8 +2375,11 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                         * to the PHY is the Ethernet MAC DT node.
                         */
                        ret = of_phy_register_fixed_link(slave_node);
-                       if (ret)
+                       if (ret) {
+                               if (ret != -EPROBE_DEFER)
+                                       dev_err(&pdev->dev, "failed to register fixed-link phy: %d\n", ret);
                                return ret;
+                       }
                        slave_data->phy_node = of_node_get(slave_node);
                } else if (parp) {
                        u32 phyid;
@@ -2397,6 +2400,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                        }
                        snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
                                 PHY_ID_FMT, mdio->name, phyid);
+                       put_device(&mdio->dev);
                } else {
                        dev_err(&pdev->dev,
                                "No slave[%d] phy_id, phy-handle, or fixed-link property\n",
@@ -2440,6 +2444,34 @@ no_phy_slave:
        return 0;
 }
 
+static void cpsw_remove_dt(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+       struct cpsw_platform_data *data = &cpsw->data;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *slave_node;
+       int i = 0;
+
+       for_each_available_child_of_node(node, slave_node) {
+               struct cpsw_slave_data *slave_data = &data->slave_data[i];
+
+               if (strcmp(slave_node->name, "slave"))
+                       continue;
+
+               if (of_phy_is_fixed_link(slave_node))
+                       of_phy_deregister_fixed_link(slave_node);
+
+               of_node_put(slave_data->phy_node);
+
+               i++;
+               if (i == data->slaves)
+                       break;
+       }
+
+       of_platform_depopulate(&pdev->dev);
+}
+
 static int cpsw_probe_dual_emac(struct cpsw_priv *priv)
 {
        struct cpsw_common              *cpsw = priv->cpsw;
@@ -2547,6 +2579,9 @@ static int cpsw_probe(struct platform_device *pdev)
        int irq;
 
        cpsw = devm_kzalloc(&pdev->dev, sizeof(struct cpsw_common), GFP_KERNEL);
+       if (!cpsw)
+               return -ENOMEM;
+
        cpsw->dev = &pdev->dev;
 
        ndev = alloc_etherdev_mq(sizeof(struct cpsw_priv), CPSW_MAX_QUEUES);
@@ -2584,11 +2619,19 @@ static int cpsw_probe(struct platform_device *pdev)
        /* Select default pin state */
        pinctrl_pm_select_default_state(&pdev->dev);
 
-       if (cpsw_probe_dt(&cpsw->data, pdev)) {
-               dev_err(&pdev->dev, "cpsw: platform data missing\n");
-               ret = -ENODEV;
+       /* Need to enable clocks with runtime PM api to access module
+        * registers
+        */
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(&pdev->dev);
                goto clean_runtime_disable_ret;
        }
+
+       ret = cpsw_probe_dt(&cpsw->data, pdev);
+       if (ret)
+               goto clean_dt_ret;
+
        data = &cpsw->data;
        cpsw->rx_ch_num = 1;
        cpsw->tx_ch_num = 1;
@@ -2608,7 +2651,7 @@ static int cpsw_probe(struct platform_device *pdev)
                                    GFP_KERNEL);
        if (!cpsw->slaves) {
                ret = -ENOMEM;
-               goto clean_runtime_disable_ret;
+               goto clean_dt_ret;
        }
        for (i = 0; i < data->slaves; i++)
                cpsw->slaves[i].slave_num = i;
@@ -2620,7 +2663,7 @@ static int cpsw_probe(struct platform_device *pdev)
        if (IS_ERR(clk)) {
                dev_err(priv->dev, "fck is not found\n");
                ret = -ENODEV;
-               goto clean_runtime_disable_ret;
+               goto clean_dt_ret;
        }
        cpsw->bus_freq_mhz = clk_get_rate(clk) / 1000000;
 
@@ -2628,26 +2671,17 @@ static int cpsw_probe(struct platform_device *pdev)
        ss_regs = devm_ioremap_resource(&pdev->dev, ss_res);
        if (IS_ERR(ss_regs)) {
                ret = PTR_ERR(ss_regs);
-               goto clean_runtime_disable_ret;
+               goto clean_dt_ret;
        }
        cpsw->regs = ss_regs;
 
-       /* Need to enable clocks with runtime PM api to access module
-        * registers
-        */
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(&pdev->dev);
-               goto clean_runtime_disable_ret;
-       }
        cpsw->version = readl(&cpsw->regs->id_ver);
-       pm_runtime_put_sync(&pdev->dev);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        cpsw->wr_regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(cpsw->wr_regs)) {
                ret = PTR_ERR(cpsw->wr_regs);
-               goto clean_runtime_disable_ret;
+               goto clean_dt_ret;
        }
 
        memset(&dma_params, 0, sizeof(dma_params));
@@ -2684,7 +2718,7 @@ static int cpsw_probe(struct platform_device *pdev)
        default:
                dev_err(priv->dev, "unknown version 0x%08x\n", cpsw->version);
                ret = -ENODEV;
-               goto clean_runtime_disable_ret;
+               goto clean_dt_ret;
        }
        for (i = 0; i < cpsw->data.slaves; i++) {
                struct cpsw_slave *slave = &cpsw->slaves[i];
@@ -2713,7 +2747,7 @@ static int cpsw_probe(struct platform_device *pdev)
        if (!cpsw->dma) {
                dev_err(priv->dev, "error initializing dma\n");
                ret = -ENOMEM;
-               goto clean_runtime_disable_ret;
+               goto clean_dt_ret;
        }
 
        cpsw->txch[0] = cpdma_chan_create(cpsw->dma, 0, cpsw_tx_handler, 0);
@@ -2811,16 +2845,23 @@ static int cpsw_probe(struct platform_device *pdev)
                ret = cpsw_probe_dual_emac(priv);
                if (ret) {
                        cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
-                       goto clean_ale_ret;
+                       goto clean_unregister_netdev_ret;
                }
        }
 
+       pm_runtime_put(&pdev->dev);
+
        return 0;
 
+clean_unregister_netdev_ret:
+       unregister_netdev(ndev);
 clean_ale_ret:
        cpsw_ale_destroy(cpsw->ale);
 clean_dma_ret:
        cpdma_ctlr_destroy(cpsw->dma);
+clean_dt_ret:
+       cpsw_remove_dt(pdev);
+       pm_runtime_put_sync(&pdev->dev);
 clean_runtime_disable_ret:
        pm_runtime_disable(&pdev->dev);
 clean_ndev_ret:
@@ -2846,7 +2887,7 @@ static int cpsw_remove(struct platform_device *pdev)
 
        cpsw_ale_destroy(cpsw->ale);
        cpdma_ctlr_destroy(cpsw->dma);
-       of_platform_depopulate(&pdev->dev);
+       cpsw_remove_dt(pdev);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        if (cpsw->data.dual_emac)
@@ -2889,6 +2930,8 @@ static int cpsw_resume(struct device *dev)
        /* Select default pin state */
        pinctrl_pm_select_default_state(dev);
 
+       /* shut up ASSERT_RTNL() warning in netif_set_real_num_tx/rx_queues */
+       rtnl_lock();
        if (cpsw->data.dual_emac) {
                int i;
 
@@ -2900,6 +2943,8 @@ static int cpsw_resume(struct device *dev)
                if (netif_running(ndev))
                        cpsw_ndo_open(ndev);
        }
+       rtnl_unlock();
+
        return 0;
 }
 #endif
index 2fd94a5bc1f3a653bebff3c5b71642fe49b97c24..481c7bf0395bfcdc3add56da8b01b61432415d81 100644 (file)
@@ -1410,6 +1410,7 @@ static int emac_dev_open(struct net_device *ndev)
        int i = 0;
        struct emac_priv *priv = netdev_priv(ndev);
        struct phy_device *phydev = NULL;
+       struct device *phy = NULL;
 
        ret = pm_runtime_get_sync(&priv->pdev->dev);
        if (ret < 0) {
@@ -1488,19 +1489,20 @@ static int emac_dev_open(struct net_device *ndev)
 
        /* use the first phy on the bus if pdata did not give us a phy id */
        if (!phydev && !priv->phy_id) {
-               struct device *phy;
-
                phy = bus_find_device(&mdio_bus_type, NULL, NULL,
                                      match_first_device);
-               if (phy)
+               if (phy) {
                        priv->phy_id = dev_name(phy);
+                       if (!priv->phy_id || !*priv->phy_id)
+                               put_device(phy);
+               }
        }
 
        if (!phydev && priv->phy_id && *priv->phy_id) {
                phydev = phy_connect(ndev, priv->phy_id,
                                     &emac_adjust_link,
                                     PHY_INTERFACE_MODE_MII);
-
+               put_device(phy);        /* reference taken by bus_find_device */
                if (IS_ERR(phydev)) {
                        dev_err(emac_dev, "could not connect to phy %s\n",
                                priv->phy_id);
@@ -1765,6 +1767,7 @@ static int davinci_emac_try_get_mac(struct platform_device *pdev,
  */
 static int davinci_emac_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        int rc = 0;
        struct resource *res, *res_ctrl;
        struct net_device *ndev;
@@ -1803,7 +1806,7 @@ static int davinci_emac_probe(struct platform_device *pdev)
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data\n");
                rc = -ENODEV;
-               goto no_pdata;
+               goto err_free_netdev;
        }
 
        /* MAC addr and PHY mask , RMII enable info from platform_data */
@@ -1939,6 +1942,10 @@ no_cpdma_chan:
                cpdma_chan_destroy(priv->rxchan);
        cpdma_ctlr_destroy(priv->dma);
 no_pdata:
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
+       of_node_put(priv->phy_node);
+err_free_netdev:
        free_netdev(ndev);
        return rc;
 }
@@ -1954,6 +1961,7 @@ static int davinci_emac_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct emac_priv *priv = netdev_priv(ndev);
+       struct device_node *np = pdev->dev.of_node;
 
        dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n");
 
@@ -1966,6 +1974,8 @@ static int davinci_emac_remove(struct platform_device *pdev)
        unregister_netdev(ndev);
        of_node_put(priv->phy_node);
        pm_runtime_disable(&pdev->dev);
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
        free_netdev(ndev);
 
        return 0;
index 446ea580ad42ff308b2c6fd305c86a25ff4057c3..928c1dca26730cfe3942b20f931007efb59452b8 100644 (file)
@@ -1694,7 +1694,7 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl)
                                pr_debug("%s: bssid matched\n", __func__);
                                break;
                        } else {
-                               pr_debug("%s: bssid unmached\n", __func__);
+                               pr_debug("%s: bssid unmatched\n", __func__);
                                continue;
                        }
                }
index 7f127dc1b7baa03b76ffaac0f2cf6dfc9e8164b5..fa32391720fec69fe5525dc897b8cf740ecf1f0b 100644 (file)
@@ -708,8 +708,7 @@ static int eth_poll(struct napi_struct *napi, int budget)
                        if (!qmgr_stat_below_low_watermark(rxq) &&
                            napi_reschedule(napi)) { /* not empty again */
 #if DEBUG_RX
-                               printk(KERN_DEBUG "%s: eth_poll"
-                                      " napi_reschedule successed\n",
+                               printk(KERN_DEBUG "%s: eth_poll napi_reschedule succeeded\n",
                                       dev->name);
 #endif
                                qmgr_disable_irq(rxq);
index 3c20e87bb7619a86b66669b1c018eed67218800e..8b4822ad27cb0d1c7fb310ca9a076f5d82e61262 100644 (file)
@@ -58,9 +58,9 @@ struct geneve_dev {
        struct hlist_node  hlist;       /* vni hash table */
        struct net         *net;        /* netns for packet i/o */
        struct net_device  *dev;        /* netdev for geneve tunnel */
-       struct geneve_sock *sock4;      /* IPv4 socket used for geneve tunnel */
+       struct geneve_sock __rcu *sock4;        /* IPv4 socket used for geneve tunnel */
 #if IS_ENABLED(CONFIG_IPV6)
-       struct geneve_sock *sock6;      /* IPv6 socket used for geneve tunnel */
+       struct geneve_sock __rcu *sock6;        /* IPv6 socket used for geneve tunnel */
 #endif
        u8                 vni[3];      /* virtual network ID for tunnel */
        u8                 ttl;         /* TTL override */
@@ -453,7 +453,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk,
 
        skb_gro_pull(skb, gh_len);
        skb_gro_postpull_rcsum(skb, gh, gh_len);
-       pp = ptype->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
        flush = 0;
 
 out_unlock:
@@ -543,9 +543,19 @@ static void __geneve_sock_release(struct geneve_sock *gs)
 
 static void geneve_sock_release(struct geneve_dev *geneve)
 {
-       __geneve_sock_release(geneve->sock4);
+       struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4);
 #if IS_ENABLED(CONFIG_IPV6)
-       __geneve_sock_release(geneve->sock6);
+       struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6);
+
+       rcu_assign_pointer(geneve->sock6, NULL);
+#endif
+
+       rcu_assign_pointer(geneve->sock4, NULL);
+       synchronize_net();
+
+       __geneve_sock_release(gs4);
+#if IS_ENABLED(CONFIG_IPV6)
+       __geneve_sock_release(gs6);
 #endif
 }
 
@@ -586,10 +596,10 @@ out:
        gs->flags = geneve->flags;
 #if IS_ENABLED(CONFIG_IPV6)
        if (ipv6)
-               geneve->sock6 = gs;
+               rcu_assign_pointer(geneve->sock6, gs);
        else
 #endif
-               geneve->sock4 = gs;
+               rcu_assign_pointer(geneve->sock4, gs);
 
        hash = geneve_net_vni_hash(geneve->vni);
        hlist_add_head_rcu(&geneve->hlist, &gs->vni_list[hash]);
@@ -603,9 +613,7 @@ static int geneve_open(struct net_device *dev)
        bool metadata = geneve->collect_md;
        int ret = 0;
 
-       geneve->sock4 = NULL;
 #if IS_ENABLED(CONFIG_IPV6)
-       geneve->sock6 = NULL;
        if (ipv6 || metadata)
                ret = geneve_sock_add(geneve, true);
 #endif
@@ -720,6 +728,9 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
        struct rtable *rt = NULL;
        __u8 tos;
 
+       if (!rcu_dereference(geneve->sock4))
+               return ERR_PTR(-EIO);
+
        memset(fl4, 0, sizeof(*fl4));
        fl4->flowi4_mark = skb->mark;
        fl4->flowi4_proto = IPPROTO_UDP;
@@ -772,11 +783,15 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
 {
        bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct geneve_dev *geneve = netdev_priv(dev);
-       struct geneve_sock *gs6 = geneve->sock6;
        struct dst_entry *dst = NULL;
        struct dst_cache *dst_cache;
+       struct geneve_sock *gs6;
        __u8 prio;
 
+       gs6 = rcu_dereference(geneve->sock6);
+       if (!gs6)
+               return ERR_PTR(-EIO);
+
        memset(fl6, 0, sizeof(*fl6));
        fl6->flowi6_mark = skb->mark;
        fl6->flowi6_proto = IPPROTO_UDP;
@@ -842,9 +857,8 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                                   struct ip_tunnel_info *info)
 {
        struct geneve_dev *geneve = netdev_priv(dev);
-       struct geneve_sock *gs4 = geneve->sock4;
+       struct geneve_sock *gs4;
        struct rtable *rt = NULL;
-       const struct iphdr *iip; /* interior IP header */
        int err = -EINVAL;
        struct flowi4 fl4;
        __u8 tos, ttl;
@@ -853,6 +867,10 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
        u32 flags = geneve->flags;
 
+       gs4 = rcu_dereference(geneve->sock4);
+       if (!gs4)
+               goto tx_error;
+
        if (geneve->collect_md) {
                if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
                        netdev_dbg(dev, "no tunnel metadata\n");
@@ -871,8 +889,6 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
        skb_reset_mac_header(skb);
 
-       iip = ip_hdr(skb);
-
        if (info) {
                const struct ip_tunnel_key *key = &info->key;
                u8 *opts = NULL;
@@ -892,7 +908,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                if (unlikely(err))
                        goto tx_error;
 
-               tos = ip_tunnel_ecn_encap(key->tos, iip, skb);
+               tos = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
                ttl = key->ttl;
                df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
        } else {
@@ -901,7 +917,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                if (unlikely(err))
                        goto tx_error;
 
-               tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, iip, skb);
+               tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, ip_hdr(skb), skb);
                ttl = geneve->ttl;
                if (!ttl && IN_MULTICAST(ntohl(fl4.daddr)))
                        ttl = 1;
@@ -932,9 +948,8 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                                    struct ip_tunnel_info *info)
 {
        struct geneve_dev *geneve = netdev_priv(dev);
-       struct geneve_sock *gs6 = geneve->sock6;
        struct dst_entry *dst = NULL;
-       const struct iphdr *iip; /* interior IP header */
+       struct geneve_sock *gs6;
        int err = -EINVAL;
        struct flowi6 fl6;
        __u8 prio, ttl;
@@ -943,6 +958,10 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
        u32 flags = geneve->flags;
 
+       gs6 = rcu_dereference(geneve->sock6);
+       if (!gs6)
+               goto tx_error;
+
        if (geneve->collect_md) {
                if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
                        netdev_dbg(dev, "no tunnel metadata\n");
@@ -959,8 +978,6 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
        skb_reset_mac_header(skb);
 
-       iip = ip_hdr(skb);
-
        if (info) {
                const struct ip_tunnel_key *key = &info->key;
                u8 *opts = NULL;
@@ -981,7 +998,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                if (unlikely(err))
                        goto tx_error;
 
-               prio = ip_tunnel_ecn_encap(key->tos, iip, skb);
+               prio = ip_tunnel_ecn_encap(key->tos, ip_hdr(skb), skb);
                ttl = key->ttl;
                label = info->key.label;
        } else {
@@ -991,7 +1008,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                        goto tx_error;
 
                prio = ip_tunnel_ecn_encap(ip6_tclass(fl6.flowlabel),
-                                          iip, skb);
+                                          ip_hdr(skb), skb);
                ttl = geneve->ttl;
                if (!ttl && ipv6_addr_is_multicast(&fl6.daddr))
                        ttl = 1;
index f0919bd3a56324c2c9f37b5f69c5132642b78f3b..c9140c3aeb67d5fc71b3911a8b2ddb51a2ef806a 100644 (file)
                                 NETIF_F_TSO | \
                                 NETIF_F_TSO6 | \
                                 NETIF_F_HW_CSUM)
+
+/* Restrict GSO size to account for NVGRE */
+#define NETVSC_GSO_MAX_SIZE    62768
+
 static int ring_size = 128;
 module_param(ring_size, int, S_IRUGO);
 MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
@@ -447,7 +451,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
         * Setup the sendside checksum offload only if this is not a
         * GSO packet.
         */
-       if (skb_is_gso(skb)) {
+       if ((net_trans_info & (INFO_TCP | INFO_UDP)) && skb_is_gso(skb)) {
                struct ndis_tcp_lso_info *lso_info;
 
                rndis_msg_size += NDIS_LSO_PPI_SIZE;
@@ -607,15 +611,18 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
               packet->total_data_buflen);
 
        skb->protocol = eth_type_trans(skb, net);
-       if (csum_info) {
-               /* We only look at the IP checksum here.
-                * Should we be dropping the packet if checksum
-                * failed? How do we deal with other checksums - TCP/UDP?
-                */
-               if (csum_info->receive.ip_checksum_succeeded)
+
+       /* skb is already created with CHECKSUM_NONE */
+       skb_checksum_none_assert(skb);
+
+       /*
+        * In Linux, the IP checksum is always checked.
+        * Do L4 checksum offload if enabled and present.
+        */
+       if (csum_info && (net->features & NETIF_F_RXCSUM)) {
+               if (csum_info->receive.tcp_checksum_succeeded ||
+                   csum_info->receive.udp_checksum_succeeded)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
-               else
-                       skb->ip_summed = CHECKSUM_NONE;
        }
 
        if (vlan_tci & VLAN_TAG_PRESENT)
@@ -696,12 +703,8 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 static void netvsc_get_drvinfo(struct net_device *net,
                               struct ethtool_drvinfo *info)
 {
-       struct net_device_context *net_device_ctx = netdev_priv(net);
-       struct hv_device *dev = net_device_ctx->device_ctx;
-
        strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
        strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
-       strlcpy(info->bus_info, vmbus_dev_name(dev), sizeof(info->bus_info));
 }
 
 static void netvsc_get_channels(struct net_device *net,
@@ -1401,6 +1404,7 @@ static int netvsc_probe(struct hv_device *dev,
        nvdev = net_device_ctx->nvdev;
        netif_set_real_num_tx_queues(net, nvdev->num_chn);
        netif_set_real_num_rx_queues(net, nvdev->num_chn);
+       netif_set_gso_max_size(net, NETVSC_GSO_MAX_SIZE);
 
        ret = register_netdev(net);
        if (ret != 0) {
index 9fa7ac9f8e68f1314b71858cc05ea497df0b5c20..f355df7cf84a819ef2a27a3956d10df96b98cb12 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/skbuff.h>
 #include <linux/of.h>
 #include <linux/irq.h>
-#include <linux/delay.h>
 #include <linux/debugfs.h>
 #include <linux/bitops.h>
 #include <linux/ieee802154.h>
index f442eb366863e034055c8cf773c9b4b0e287ae87..dfbc4ef6d507b09905f5f9f57717acdebaaa53be 100644 (file)
@@ -497,6 +497,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
        struct net_device *phy_dev;
        int err;
        u16 mode = IPVLAN_MODE_L3;
+       bool create = false;
 
        if (!tb[IFLA_LINK])
                return -EINVAL;
@@ -513,6 +514,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
                err = ipvlan_port_create(phy_dev);
                if (err < 0)
                        return err;
+               create = true;
        }
 
        if (data && data[IFLA_IPVLAN_MODE])
@@ -536,22 +538,29 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
 
        err = register_netdevice(dev);
        if (err < 0)
-               return err;
+               goto destroy_ipvlan_port;
 
        err = netdev_upper_dev_link(phy_dev, dev);
        if (err) {
-               unregister_netdevice(dev);
-               return err;
+               goto unregister_netdev;
        }
        err = ipvlan_set_port_mode(port, mode);
        if (err) {
-               unregister_netdevice(dev);
-               return err;
+               goto unlink_netdev;
        }
 
        list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans);
        netif_stacked_transfer_operstate(phy_dev, dev);
        return 0;
+
+unlink_netdev:
+       netdev_upper_dev_unlink(phy_dev, dev);
+unregister_netdev:
+       unregister_netdevice(dev);
+destroy_ipvlan_port:
+       if (create)
+               ipvlan_port_destroy(phy_dev);
+       return err;
 }
 
 static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
index a198946bc54fda6ce8df93c2d4c12b22d32eb117..8716b8c07febf5669b5fe21d78f1b68b4d10ea3f 100644 (file)
@@ -1723,6 +1723,7 @@ static int irda_usb_probe(struct usb_interface *intf,
        /* Don't change this buffer size and allocation without doing
         * some heavy and complete testing. Don't ask why :-(
         * Jean II */
+       ret = -ENOMEM;
        self->speed_buff = kzalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
        if (!self->speed_buff)
                goto err_out_3;
index 4e3d2e7c697c76f483eb264b1c5da9244eb434c6..e8c3a8c32534b41d3e44397217da9ae68565b95d 100644 (file)
@@ -518,7 +518,9 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
                
                mtt = irda_get_mtt(skb);
                pr_debug("%s(%ld), mtt=%d\n", __func__ , jiffies, mtt);
-                       if (mtt)
+                       if (mtt > 1000)
+                               mdelay(mtt/1000);
+                       else if (mtt)
                                udelay(mtt);
 
                        /* Enable DMA interrupt */
index 3ea47f28e143bd03113215f45a0ad7b7eb9ceb61..d2e61e0029262073b56e3f2cb81e7bf3e00a728e 100644 (file)
@@ -397,6 +397,14 @@ static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb)
 #define DEFAULT_ENCRYPT false
 #define DEFAULT_ENCODING_SA 0
 
+static bool send_sci(const struct macsec_secy *secy)
+{
+       const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+
+       return tx_sc->send_sci ||
+               (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb);
+}
+
 static sci_t make_sci(u8 *addr, __be16 port)
 {
        sci_t sci;
@@ -437,15 +445,15 @@ static unsigned int macsec_extra_len(bool sci_present)
 
 /* Fill SecTAG according to IEEE 802.1AE-2006 10.5.3 */
 static void macsec_fill_sectag(struct macsec_eth_header *h,
-                              const struct macsec_secy *secy, u32 pn)
+                              const struct macsec_secy *secy, u32 pn,
+                              bool sci_present)
 {
        const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
 
-       memset(&h->tci_an, 0, macsec_sectag_len(tx_sc->send_sci));
+       memset(&h->tci_an, 0, macsec_sectag_len(sci_present));
        h->eth.h_proto = htons(ETH_P_MACSEC);
 
-       if (tx_sc->send_sci ||
-           (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb)) {
+       if (sci_present) {
                h->tci_an |= MACSEC_TCI_SC;
                memcpy(&h->secure_channel_id, &secy->sci,
                       sizeof(h->secure_channel_id));
@@ -650,6 +658,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
        struct macsec_tx_sc *tx_sc;
        struct macsec_tx_sa *tx_sa;
        struct macsec_dev *macsec = macsec_priv(dev);
+       bool sci_present;
        u32 pn;
 
        secy = &macsec->secy;
@@ -687,7 +696,8 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
 
        unprotected_len = skb->len;
        eth = eth_hdr(skb);
-       hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(tx_sc->send_sci));
+       sci_present = send_sci(secy);
+       hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(sci_present));
        memmove(hh, eth, 2 * ETH_ALEN);
 
        pn = tx_sa_update_pn(tx_sa, secy);
@@ -696,7 +706,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
                kfree_skb(skb);
                return ERR_PTR(-ENOLINK);
        }
-       macsec_fill_sectag(hh, secy, pn);
+       macsec_fill_sectag(hh, secy, pn, sci_present);
        macsec_set_shortlen(hh, unprotected_len - 2 * ETH_ALEN);
 
        skb_put(skb, secy->icv_len);
@@ -726,10 +736,10 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
        skb_to_sgvec(skb, sg, 0, skb->len);
 
        if (tx_sc->encrypt) {
-               int len = skb->len - macsec_hdr_len(tx_sc->send_sci) -
+               int len = skb->len - macsec_hdr_len(sci_present) -
                          secy->icv_len;
                aead_request_set_crypt(req, sg, sg, len, iv);
-               aead_request_set_ad(req, macsec_hdr_len(tx_sc->send_sci));
+               aead_request_set_ad(req, macsec_hdr_len(sci_present));
        } else {
                aead_request_set_crypt(req, sg, sg, 0, iv);
                aead_request_set_ad(req, skb->len - secy->icv_len);
index 3234fcdea31745046cc5a7ac20f2ca676ddcb2e4..26d6f0bbe14bf9b35c778f0f3516a2e3065954b2 100644 (file)
@@ -623,7 +623,8 @@ hash_add:
        return 0;
 
 clear_multi:
-       dev_set_allmulti(lowerdev, -1);
+       if (dev->flags & IFF_ALLMULTI)
+               dev_set_allmulti(lowerdev, -1);
 del_unicast:
        dev_uc_del(lowerdev, dev->dev_addr);
 out:
@@ -1278,6 +1279,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
        struct net_device *lowerdev;
        int err;
        int macmode;
+       bool create = false;
 
        if (!tb[IFLA_LINK])
                return -EINVAL;
@@ -1304,12 +1306,18 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
                err = macvlan_port_create(lowerdev);
                if (err < 0)
                        return err;
+               create = true;
        }
        port = macvlan_port_get_rtnl(lowerdev);
 
        /* Only 1 macvlan device can be created in passthru mode */
-       if (port->passthru)
-               return -EINVAL;
+       if (port->passthru) {
+               /* The macvlan port must be not created this time,
+                * still goto destroy_macvlan_port for readability.
+                */
+               err = -EINVAL;
+               goto destroy_macvlan_port;
+       }
 
        vlan->lowerdev = lowerdev;
        vlan->dev      = dev;
@@ -1325,24 +1333,28 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
                vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
 
        if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
-               if (port->count)
-                       return -EINVAL;
+               if (port->count) {
+                       err = -EINVAL;
+                       goto destroy_macvlan_port;
+               }
                port->passthru = true;
                eth_hw_addr_inherit(dev, lowerdev);
        }
 
        if (data && data[IFLA_MACVLAN_MACADDR_MODE]) {
-               if (vlan->mode != MACVLAN_MODE_SOURCE)
-                       return -EINVAL;
+               if (vlan->mode != MACVLAN_MODE_SOURCE) {
+                       err = -EINVAL;
+                       goto destroy_macvlan_port;
+               }
                macmode = nla_get_u32(data[IFLA_MACVLAN_MACADDR_MODE]);
                err = macvlan_changelink_sources(vlan, macmode, data);
                if (err)
-                       return err;
+                       goto destroy_macvlan_port;
        }
 
        err = register_netdevice(dev);
        if (err < 0)
-               return err;
+               goto destroy_macvlan_port;
 
        dev->priv_flags |= IFF_MACVLAN;
        err = netdev_upper_dev_link(lowerdev, dev);
@@ -1357,7 +1369,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
 
 unregister_netdev:
        unregister_netdevice(dev);
-
+destroy_macvlan_port:
+       if (create)
+               macvlan_port_destroy(port->dev);
        return err;
 }
 EXPORT_SYMBOL_GPL(macvlan_common_newlink);
index 070e3290aa6efea6fcb505cdf0860a4dce676b74..7869b0651576fa6432b9608adb906fc7e1fccd26 100644 (file)
@@ -491,7 +491,13 @@ static int macvtap_newlink(struct net *src_net,
        /* Don't put anything that may fail after macvlan_common_newlink
         * because we can't undo what it does.
         */
-       return macvlan_common_newlink(src_net, dev, tb, data);
+       err = macvlan_common_newlink(src_net, dev, tb, data);
+       if (err) {
+               netdev_rx_handler_unregister(dev);
+               return err;
+       }
+
+       return 0;
 }
 
 static void macvtap_dellink(struct net_device *dev,
@@ -736,13 +742,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
 
        if (zerocopy)
                err = zerocopy_sg_from_iter(skb, from);
-       else {
+       else
                err = skb_copy_datagram_from_iter(skb, 0, from, len);
-               if (!err && m && m->msg_control) {
-                       struct ubuf_info *uarg = m->msg_control;
-                       uarg->callback(uarg, false);
-               }
-       }
 
        if (err)
                goto err_kfree;
@@ -773,7 +774,11 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                skb_shinfo(skb)->destructor_arg = m->msg_control;
                skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
                skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
+       } else if (m && m->msg_control) {
+               struct ubuf_info *uarg = m->msg_control;
+               uarg->callback(uarg, false);
        }
+
        if (vlan) {
                skb->dev = vlan->dev;
                dev_queue_xmit(skb);
index f279a897a5c7fe0e875fb8b058f4c00ae3059f62..a52b560e428b86cd5e782749725875a127a52ea7 100644 (file)
 #define AT803X_MMD_ACCESS_CONTROL              0x0D
 #define AT803X_MMD_ACCESS_CONTROL_DATA         0x0E
 #define AT803X_FUNC_DATA                       0x4003
+#define AT803X_REG_CHIP_CONFIG                 0x1f
+#define AT803X_BT_BX_REG_SEL                   0x8000
 
 #define AT803X_DEBUG_ADDR                      0x1D
 #define AT803X_DEBUG_DATA                      0x1E
 
+#define AT803X_MODE_CFG_MASK                   0x0F
+#define AT803X_MODE_CFG_SGMII                  0x01
+
+#define AT803X_PSSR                    0x11    /*PHY-Specific Status Register*/
+#define AT803X_PSSR_MR_AN_COMPLETE     0x0200
+
 #define AT803X_DEBUG_REG_0                     0x00
 #define AT803X_DEBUG_RX_CLK_DLY_EN             BIT(15)
 
 #define AT803X_DEBUG_REG_5                     0x05
 #define AT803X_DEBUG_TX_CLK_DLY_EN             BIT(8)
 
-#define AT803X_REG_CHIP_CONFIG                 0x1f
-#define AT803X_BT_BX_REG_SEL                   0x8000
-
 #define ATH8030_PHY_ID 0x004dd076
 #define ATH8031_PHY_ID 0x004dd074
 #define ATH8035_PHY_ID 0x004dd072
@@ -209,7 +214,6 @@ static int at803x_suspend(struct phy_device *phydev)
 {
        int value;
        int wol_enabled;
-       int ccr;
 
        mutex_lock(&phydev->lock);
 
@@ -225,16 +229,6 @@ static int at803x_suspend(struct phy_device *phydev)
 
        phy_write(phydev, MII_BMCR, value);
 
-       if (phydev->interface != PHY_INTERFACE_MODE_SGMII)
-               goto done;
-
-       /* also power-down SGMII interface */
-       ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
-       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
-       phy_write(phydev, MII_BMCR, phy_read(phydev, MII_BMCR) | BMCR_PDOWN);
-       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
-
-done:
        mutex_unlock(&phydev->lock);
 
        return 0;
@@ -243,7 +237,6 @@ done:
 static int at803x_resume(struct phy_device *phydev)
 {
        int value;
-       int ccr;
 
        mutex_lock(&phydev->lock);
 
@@ -251,17 +244,6 @@ static int at803x_resume(struct phy_device *phydev)
        value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
        phy_write(phydev, MII_BMCR, value);
 
-       if (phydev->interface != PHY_INTERFACE_MODE_SGMII)
-               goto done;
-
-       /* also power-up SGMII interface */
-       ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
-       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
-       value = phy_read(phydev, MII_BMCR) & ~(BMCR_PDOWN | BMCR_ISOLATE);
-       phy_write(phydev, MII_BMCR, value);
-       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
-
-done:
        mutex_unlock(&phydev->lock);
 
        return 0;
@@ -381,6 +363,36 @@ static void at803x_link_change_notify(struct phy_device *phydev)
        }
 }
 
+static int at803x_aneg_done(struct phy_device *phydev)
+{
+       int ccr;
+
+       int aneg_done = genphy_aneg_done(phydev);
+       if (aneg_done != BMSR_ANEGCOMPLETE)
+               return aneg_done;
+
+       /*
+        * in SGMII mode, if copper side autoneg is successful,
+        * also check SGMII side autoneg result
+        */
+       ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+       if ((ccr & AT803X_MODE_CFG_MASK) != AT803X_MODE_CFG_SGMII)
+               return aneg_done;
+
+       /* switch to SGMII/fiber page */
+       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
+
+       /* check if the SGMII link is OK. */
+       if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) {
+               pr_warn("803x_aneg_done: SGMII link is not ok\n");
+               aneg_done = 0;
+       }
+       /* switch back to copper page */
+       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
+
+       return aneg_done;
+}
+
 static struct phy_driver at803x_driver[] = {
 {
        /* ATHEROS 8035 */
@@ -432,6 +444,7 @@ static struct phy_driver at803x_driver[] = {
        .flags                  = PHY_HAS_INTERRUPT,
        .config_aneg            = genphy_config_aneg,
        .read_status            = genphy_read_status,
+       .aneg_done              = at803x_aneg_done,
        .ack_interrupt          = &at803x_ack_interrupt,
        .config_intr            = &at803x_config_intr,
 } };
index 03d54c4adc881fc2d65de40a399096687c5b4444..800b39f0627943343c4276de637b30be4692352f 100644 (file)
@@ -19,6 +19,7 @@
 #define TI_DP83848C_PHY_ID             0x20005ca0
 #define NS_DP83848C_PHY_ID             0x20005c90
 #define TLK10X_PHY_ID                  0x2000a210
+#define TI_DP83822_PHY_ID              0x2000a240
 
 /* Registers */
 #define DP83848_MICR                   0x11 /* MII Interrupt Control Register */
@@ -77,6 +78,7 @@ static struct mdio_device_id __maybe_unused dp83848_tbl[] = {
        { TI_DP83848C_PHY_ID, 0xfffffff0 },
        { NS_DP83848C_PHY_ID, 0xfffffff0 },
        { TLK10X_PHY_ID, 0xfffffff0 },
+       { TI_DP83822_PHY_ID, 0xfffffff0 },
        { }
 };
 MODULE_DEVICE_TABLE(mdio, dp83848_tbl);
@@ -105,6 +107,7 @@ static struct phy_driver dp83848_driver[] = {
        DP83848_PHY_DRIVER(TI_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY"),
        DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY"),
        DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY"),
+       DP83848_PHY_DRIVER(TI_DP83822_PHY_ID, "TI DP83822 10/100 Mbps PHY"),
 };
 module_phy_driver(dp83848_driver);
 
index c649c101bbaba97ec44255b9ee1e7a878c26ada5..eb51672106811e35ee0a7b3f0578560e16bc3670 100644 (file)
@@ -279,7 +279,7 @@ EXPORT_SYMBOL_GPL(fixed_phy_register);
 void fixed_phy_unregister(struct phy_device *phy)
 {
        phy_device_remove(phy);
-
+       of_node_put(phy->mdio.dev.of_node);
        fixed_phy_del(phy->mdio.addr);
 }
 EXPORT_SYMBOL_GPL(fixed_phy_unregister);
index 081df68d2ce1467550657996e0a7268436e5323a..ea92d524d5a814ff22727eefa1818c0b0fd47a32 100644 (file)
@@ -318,12 +318,12 @@ static int ksz8041_config_init(struct phy_device *phydev)
        /* Limit supported and advertised modes in fiber mode */
        if (of_property_read_bool(of_node, "micrel,fiber-mode")) {
                phydev->dev_flags |= MICREL_PHY_FXEN;
-               phydev->supported &= SUPPORTED_FIBRE |
-                                    SUPPORTED_100baseT_Full |
+               phydev->supported &= SUPPORTED_100baseT_Full |
                                     SUPPORTED_100baseT_Half;
-               phydev->advertising &= ADVERTISED_FIBRE |
-                                      ADVERTISED_100baseT_Full |
+               phydev->supported |= SUPPORTED_FIBRE;
+               phydev->advertising &= ADVERTISED_100baseT_Full |
                                       ADVERTISED_100baseT_Half;
+               phydev->advertising |= ADVERTISED_FIBRE;
                phydev->autoneg = AUTONEG_DISABLE;
        }
 
index e977ba931878e77cb149fd5a66c5618f723500a3..c4ceb082e970e5d2a7d3b8c2c2f75813d52fbcff 100644 (file)
@@ -723,6 +723,7 @@ struct phy_device *phy_connect(struct net_device *dev, const char *bus_id,
        phydev = to_phy_device(d);
 
        rc = phy_connect_direct(dev, phydev, handler, interface);
+       put_device(d);
        if (rc)
                return ERR_PTR(rc);
 
@@ -856,11 +857,17 @@ EXPORT_SYMBOL(phy_attached_print);
 int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
                      u32 flags, phy_interface_t interface)
 {
+       struct module *ndev_owner = dev->dev.parent->driver->owner;
        struct mii_bus *bus = phydev->mdio.bus;
        struct device *d = &phydev->mdio.dev;
        int err;
 
-       if (!try_module_get(bus->owner)) {
+       /* For Ethernet device drivers that register their own MDIO bus, we
+        * will have bus->owner match ndev_mod, so we do not want to increment
+        * our own module->refcnt here, otherwise we would not be able to
+        * unload later on.
+        */
+       if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
                dev_err(&dev->dev, "failed to get the bus module\n");
                return -EIO;
        }
@@ -920,7 +927,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
 
 error:
        put_device(d);
-       module_put(bus->owner);
+       if (ndev_owner != bus->owner)
+               module_put(bus->owner);
        return err;
 }
 EXPORT_SYMBOL(phy_attach_direct);
@@ -953,6 +961,7 @@ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
        phydev = to_phy_device(d);
 
        rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
+       put_device(d);
        if (rc)
                return ERR_PTR(rc);
 
@@ -969,6 +978,8 @@ EXPORT_SYMBOL(phy_attach);
  */
 void phy_detach(struct phy_device *phydev)
 {
+       struct net_device *dev = phydev->attached_dev;
+       struct module *ndev_owner = dev->dev.parent->driver->owner;
        struct mii_bus *bus;
        int i;
 
@@ -996,7 +1007,8 @@ void phy_detach(struct phy_device *phydev)
        bus = phydev->mdio.bus;
 
        put_device(&phydev->mdio.dev);
-       module_put(bus->owner);
+       if (ndev_owner != bus->owner)
+               module_put(bus->owner);
 }
 EXPORT_SYMBOL(phy_detach);
 
index aadd6e9f54adc5b2bb9947dd8ad4ac2f5fffda5f..9cbe645e3d89c98ca5c7974f2d0e39016e71cfa8 100644 (file)
@@ -102,15 +102,19 @@ static int rtl8211f_config_init(struct phy_device *phydev)
        if (ret < 0)
                return ret;
 
-       if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
-               /* enable TXDLY */
-               phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
-               reg = phy_read(phydev, 0x11);
+       phy_write(phydev, RTL8211F_PAGE_SELECT, 0xd08);
+       reg = phy_read(phydev, 0x11);
+
+       /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+           phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
                reg |= RTL8211F_TX_DELAY;
-               phy_write(phydev, 0x11, reg);
-               /* restore to default page 0 */
-               phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
-       }
+       else
+               reg &= ~RTL8211F_TX_DELAY;
+
+       phy_write(phydev, 0x11, reg);
+       /* restore to default page 0 */
+       phy_write(phydev, RTL8211F_PAGE_SELECT, 0x0);
 
        return 0;
 }
index 2e37eb337d4868715606b92dab65cfeb60a37679..24b4a09468dd0f5784d6bfd32814a73f6302a1e2 100644 (file)
 /* Vitesse Extended Page Access Register */
 #define MII_VSC82X4_EXT_PAGE_ACCESS    0x1f
 
+/* Vitesse VSC8601 Extended PHY Control Register 1 */
+#define MII_VSC8601_EPHY_CTL           0x17
+#define MII_VSC8601_EPHY_CTL_RGMII_SKEW        (1 << 8)
+
 #define PHY_ID_VSC8234                 0x000fc620
 #define PHY_ID_VSC8244                 0x000fc6c0
 #define PHY_ID_VSC8514                 0x00070670
@@ -111,6 +115,34 @@ static int vsc824x_config_init(struct phy_device *phydev)
        return err;
 }
 
+/* This adds a skew for both TX and RX clocks, so the skew should only be
+ * applied to "rgmii-id" interfaces. It may not work as expected
+ * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */
+static int vsc8601_add_skew(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = phy_read(phydev, MII_VSC8601_EPHY_CTL);
+       if (ret < 0)
+               return ret;
+
+       ret |= MII_VSC8601_EPHY_CTL_RGMII_SKEW;
+       return phy_write(phydev, MII_VSC8601_EPHY_CTL, ret);
+}
+
+static int vsc8601_config_init(struct phy_device *phydev)
+{
+       int ret = 0;
+
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+               ret = vsc8601_add_skew(phydev);
+
+       if (ret < 0)
+               return ret;
+
+       return genphy_config_init(phydev);
+}
+
 static int vsc824x_ack_interrupt(struct phy_device *phydev)
 {
        int err = 0;
@@ -275,7 +307,7 @@ static struct phy_driver vsc82xx_driver[] = {
        .phy_id_mask    = 0x000ffff0,
        .features       = PHY_GBIT_FEATURES,
        .flags          = PHY_HAS_INTERRUPT,
-       .config_init    = &genphy_config_init,
+       .config_init    = &vsc8601_config_init,
        .config_aneg    = &genphy_config_aneg,
        .read_status    = &genphy_read_status,
        .ack_interrupt  = &vsc824x_ack_interrupt,
index 8093e39ae263a7bd954682125221189499206b7c..db6acecabeaa3f51344ffc366ec0a502da4fea08 100644 (file)
@@ -1246,13 +1246,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
 
        if (zerocopy)
                err = zerocopy_sg_from_iter(skb, from);
-       else {
+       else
                err = skb_copy_datagram_from_iter(skb, 0, from, len);
-               if (!err && msg_control) {
-                       struct ubuf_info *uarg = msg_control;
-                       uarg->callback(uarg, false);
-               }
-       }
 
        if (err) {
                this_cpu_inc(tun->pcpu_stats->rx_dropped);
@@ -1298,6 +1293,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                skb_shinfo(skb)->destructor_arg = msg_control;
                skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
                skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
+       } else if (msg_control) {
+               struct ubuf_info *uarg = msg_control;
+               uarg->callback(uarg, false);
        }
 
        skb_reset_network_header(skb);
index f79eb12c326aacf2ed62b021b0b4d87bfa5c71e7..125cff57c759e40f50337fb1c5887f77c0c78090 100644 (file)
@@ -433,13 +433,13 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
        mutex_lock(&dev->phy_mutex);
        do {
                ret = asix_set_sw_mii(dev, 0);
-               if (ret == -ENODEV)
+               if (ret == -ENODEV || ret == -ETIMEDOUT)
                        break;
                usleep_range(1000, 1100);
                ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
                                    0, 0, 1, &smsr, 0);
        } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
-       if (ret == -ENODEV) {
+       if (ret == -ENODEV || ret == -ETIMEDOUT) {
                mutex_unlock(&dev->phy_mutex);
                return ret;
        }
@@ -497,13 +497,13 @@ int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)
        mutex_lock(&dev->phy_mutex);
        do {
                ret = asix_set_sw_mii(dev, 1);
-               if (ret == -ENODEV)
+               if (ret == -ENODEV || ret == -ETIMEDOUT)
                        break;
                usleep_range(1000, 1100);
                ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
                                    0, 0, 1, &smsr, 1);
        } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
-       if (ret == -ENODEV) {
+       if (ret == -ENODEV || ret == -ETIMEDOUT) {
                mutex_unlock(&dev->phy_mutex);
                return ret;
        }
index cce24950a0ab65f795230b5d5fa08d09e69dd139..dc7b6392e75ab19bf72dc4b2f330b38d97c7e38b 100644 (file)
@@ -603,12 +603,12 @@ static void ax88772_suspend(struct usbnet *dev)
        u16 medium;
 
        /* Stop MAC operation */
-       medium = asix_read_medium_status(dev, 0);
+       medium = asix_read_medium_status(dev, 1);
        medium &= ~AX_MEDIUM_RE;
-       asix_write_medium_mode(dev, medium, 0);
+       asix_write_medium_mode(dev, medium, 1);
 
        netdev_dbg(dev->net, "ax88772_suspend: medium=0x%04x\n",
-                  asix_read_medium_status(dev, 0));
+                  asix_read_medium_status(dev, 1));
 
        /* Preserve BMCR for restoring */
        priv->presvd_phy_bmcr =
index e6338c16081a5d66c11ad400e876ca7b6c7bcd40..8a6675d92b98c763609ade909c0fdd77592f953f 100644 (file)
@@ -1656,6 +1656,19 @@ static const struct driver_info ax88178a_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info cypress_GX3_info = {
+       .description = "Cypress GX3 SuperSpeed to Gigabit Ethernet Controller",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct driver_info dlink_dub1312_info = {
        .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
        .bind = ax88179_bind,
@@ -1717,6 +1730,10 @@ static const struct usb_device_id products[] = {
        /* ASIX AX88178A 10/100/1000 */
        USB_DEVICE(0x0b95, 0x178a),
        .driver_info = (unsigned long)&ax88178a_info,
+}, {
+       /* Cypress GX3 SuperSpeed to Gigabit Ethernet Bridge Controller */
+       USB_DEVICE(0x04b4, 0x3610),
+       .driver_info = (unsigned long)&cypress_GX3_info,
 }, {
        /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
        USB_DEVICE(0x2001, 0x4a00),
index c47ec0a04c8e5f9ff4d77cf8fade7717ca9cdb75..dd623f6744875969e7eb657612ab1a85b85689eb 100644 (file)
@@ -388,12 +388,6 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
        case USB_CDC_NOTIFY_NETWORK_CONNECTION:
                netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
                          event->wValue ? "on" : "off");
-
-               /* Work-around for devices with broken off-notifications */
-               if (event->wValue &&
-                   !test_bit(__LINK_STATE_NOCARRIER, &dev->net->state))
-                       usbnet_link_change(dev, 0, 0);
-
                usbnet_link_change(dev, !!event->wValue, 0);
                break;
        case USB_CDC_NOTIFY_SPEED_CHANGE:       /* tx/rx rates */
@@ -466,6 +460,36 @@ static int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        return 1;
 }
 
+/* Ensure correct link state
+ *
+ * Some devices (ZTE MF823/831/910) export two carrier on notifications when
+ * connected. This causes the link state to be incorrect. Work around this by
+ * always setting the state to off, then on.
+ */
+void usbnet_cdc_zte_status(struct usbnet *dev, struct urb *urb)
+{
+       struct usb_cdc_notification *event;
+
+       if (urb->actual_length < sizeof(*event))
+               return;
+
+       event = urb->transfer_buffer;
+
+       if (event->bNotificationType != USB_CDC_NOTIFY_NETWORK_CONNECTION) {
+               usbnet_cdc_status(dev, urb);
+               return;
+       }
+
+       netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
+                 event->wValue ? "on" : "off");
+
+       if (event->wValue &&
+           netif_carrier_ok(dev->net))
+               netif_carrier_off(dev->net);
+
+       usbnet_link_change(dev, !!event->wValue, 0);
+}
+
 static const struct driver_info        cdc_info = {
        .description =  "CDC Ethernet Device",
        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
@@ -481,7 +505,7 @@ static const struct driver_info     zte_cdc_info = {
        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
        .bind =         usbnet_cdc_zte_bind,
        .unbind =       usbnet_cdc_unbind,
-       .status =       usbnet_cdc_status,
+       .status =       usbnet_cdc_zte_status,
        .set_rx_mode =  usbnet_cdc_update_filter,
        .manage_power = usbnet_manage_power,
        .rx_fixup = usbnet_cdc_zte_rx_fixup,
index 96a5028621c8b320c2d6feca5911f40cde10771e..3a98f3762a4c81debc023d04b9c01876c6cbdc5f 100644 (file)
@@ -602,6 +602,21 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = {
        .data = CDC_NCM_FLAG_NDP_TO_END,
 };
 
+/* Some modems (e.g. Telit LE922A6) do not work properly with altsetting
+ * toggle done in cdc_ncm_bind_common. CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
+ * flag is used to avoid this procedure.
+ */
+static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = {
+       .description = "CDC MBIM",
+       .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+       .bind = cdc_mbim_bind,
+       .unbind = cdc_mbim_unbind,
+       .manage_power = cdc_mbim_manage_power,
+       .rx_fixup = cdc_mbim_rx_fixup,
+       .tx_fixup = cdc_mbim_tx_fixup,
+       .data = CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE,
+};
+
 static const struct usb_device_id mbim_devs[] = {
        /* This duplicate NCM entry is intentional. MBIM devices can
         * be disguised as NCM by default, and this is necessary to
@@ -626,6 +641,12 @@ static const struct usb_device_id mbim_devs[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end,
        },
+
+       /* Telit LE922A6 in MBIM composition */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1041, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
+       },
+
        /* default entry */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info_zlp,
index 877c9516e78174dc41bd1e9d3f4c506d193134a9..afbfc0f656f331e82d4c8a528134ff892e2a8635 100644 (file)
@@ -839,11 +839,18 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
 
        iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
 
+       /* Device-specific flags */
+       ctx->drvflags = drvflags;
+
        /* Reset data interface. Some devices will not reset properly
         * unless they are configured first.  Toggle the altsetting to
-        * force a reset
+        * force a reset.
+        * Some other devices do not work properly with this procedure
+        * that can be avoided using quirk CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
         */
-       usb_set_interface(dev->udev, iface_no, data_altsetting);
+       if (!(ctx->drvflags & CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE))
+               usb_set_interface(dev->udev, iface_no, data_altsetting);
+
        temp = usb_set_interface(dev->udev, iface_no, 0);
        if (temp) {
                dev_dbg(&intf->dev, "set interface failed\n");
@@ -890,9 +897,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        /* finish setting up the device specific data */
        cdc_ncm_setup(dev);
 
-       /* Device-specific flags */
-       ctx->drvflags = drvflags;
-
        /* Allocate the delayed NDP if needed. */
        if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
index 5662babf05832e8641da4b6aaa7bce9da4fdbc9c..3e37724d30ae7efa2153f53fab3b21dc6cac5af7 100644 (file)
@@ -151,7 +151,7 @@ kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
 
        status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr);
 
-       if (status < 0) {
+       if (status) {
                usb_set_intfdata(intf, NULL);
                usb_driver_release_interface(driver_of(intf), intf);
                return status;
index db558b8b32fe5ba7f9fb71129d41cf806b6c08f4..f33460cec79f394238e8f489453d19d722245009 100644 (file)
@@ -3395,6 +3395,7 @@ static int lan78xx_probe(struct usb_interface *intf,
        if (buf) {
                dev->urb_intr = usb_alloc_urb(0, GFP_KERNEL);
                if (!dev->urb_intr) {
+                       ret = -ENOMEM;
                        kfree(buf);
                        goto out3;
                } else {
index 3ff76c6db4f6d7d8bf7e5baee03cdbcf38976d76..6fe1cdb0174f6cf91f8445dbe86a3e977d327255 100644 (file)
@@ -894,6 +894,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)},    /* Alcatel L800MA */
        {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
        {QMI_FIXED_INTF(0x2357, 0x9000, 4)},    /* TP-LINK MA260 */
+       {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */
        {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
        {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)},    /* Telit LE920 */
        {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)},    /* XS Stick W100-2 from 4G Systems */
index 44d439f50961d676694107017073ca1323543f99..efb84f0924922af5caea946423e69c59f88c754d 100644 (file)
@@ -1730,7 +1730,7 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
        u8 checksum = CHECKSUM_NONE;
        u32 opts2, opts3;
 
-       if (tp->version == RTL_VER_01)
+       if (tp->version == RTL_VER_01 || tp->version == RTL_VER_02)
                goto return_result;
 
        opts2 = le32_to_cpu(rx_desc->opts2);
@@ -1745,7 +1745,7 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
                        checksum = CHECKSUM_NONE;
                else
                        checksum = CHECKSUM_UNNECESSARY;
-       } else if (RD_IPV6_CS) {
+       } else if (opts2 & RD_IPV6_CS) {
                if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF))
                        checksum = CHECKSUM_UNNECESSARY;
                else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF))
@@ -3266,10 +3266,8 @@ static int rtl8152_open(struct net_device *netdev)
                goto out;
 
        res = usb_autopm_get_interface(tp->intf);
-       if (res < 0) {
-               free_all_mem(tp);
-               goto out;
-       }
+       if (res < 0)
+               goto out_free;
 
        mutex_lock(&tp->control);
 
@@ -3285,10 +3283,9 @@ static int rtl8152_open(struct net_device *netdev)
                        netif_device_detach(tp->netdev);
                netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
                           res);
-               free_all_mem(tp);
-       } else {
-               napi_enable(&tp->napi);
+               goto out_unlock;
        }
+       napi_enable(&tp->napi);
 
        mutex_unlock(&tp->control);
 
@@ -3297,7 +3294,13 @@ static int rtl8152_open(struct net_device *netdev)
        tp->pm_notifier.notifier_call = rtl_notifier;
        register_pm_notifier(&tp->pm_notifier);
 #endif
+       return 0;
 
+out_unlock:
+       mutex_unlock(&tp->control);
+       usb_autopm_put_interface(tp->intf);
+out_free:
+       free_all_mem(tp);
 out:
        return res;
 }
index fad84f3f41099dce6fb62399b0df9ac6be857318..cbf1c613c67aefc48692079a5f11f64c34728fa5 100644 (file)
@@ -969,12 +969,17 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
        struct virtnet_info *vi = netdev_priv(dev);
        struct virtio_device *vdev = vi->vdev;
        int ret;
-       struct sockaddr *addr = p;
+       struct sockaddr *addr;
        struct scatterlist sg;
 
-       ret = eth_prepare_mac_addr_change(dev, p);
+       addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+       if (!addr)
+               return -ENOMEM;
+       memcpy(addr, p, sizeof(*addr));
+
+       ret = eth_prepare_mac_addr_change(dev, addr);
        if (ret)
-               return ret;
+               goto out;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
                sg_init_one(&sg, addr->sa_data, dev->addr_len);
@@ -982,7 +987,8 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
                                          VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) {
                        dev_warn(&vdev->dev,
                                 "Failed to set mac address by vq command.\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
        } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) &&
                   !virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
@@ -996,8 +1002,11 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
        }
 
        eth_commit_mac_addr_change(dev, p);
+       ret = 0;
 
-       return 0;
+out:
+       kfree(addr);
+       return ret;
 }
 
 static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
@@ -1497,6 +1506,11 @@ static void virtnet_free_queues(struct virtnet_info *vi)
                netif_napi_del(&vi->rq[i].napi);
        }
 
+       /* We called napi_hash_del() before netif_napi_del(),
+        * we need to respect an RCU grace period before freeing vi->rq
+        */
+       synchronize_net();
+
        kfree(vi->rq);
        kfree(vi->sq);
 }
@@ -2038,23 +2052,33 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
+#define VIRTNET_FEATURES \
+       VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, \
+       VIRTIO_NET_F_MAC, \
+       VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, \
+       VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, \
+       VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, \
+       VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
+       VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
+       VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
+       VIRTIO_NET_F_CTRL_MAC_ADDR, \
+       VIRTIO_NET_F_MTU
+
 static unsigned int features[] = {
-       VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM,
-       VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
-       VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
-       VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
-       VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
-       VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
-       VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
-       VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
-       VIRTIO_NET_F_CTRL_MAC_ADDR,
+       VIRTNET_FEATURES,
+};
+
+static unsigned int features_legacy[] = {
+       VIRTNET_FEATURES,
+       VIRTIO_NET_F_GSO,
        VIRTIO_F_ANY_LAYOUT,
-       VIRTIO_NET_F_MTU,
 };
 
 static struct virtio_driver virtio_net_driver = {
        .feature_table = features,
        .feature_table_size = ARRAY_SIZE(features),
+       .feature_table_legacy = features_legacy,
+       .feature_table_size_legacy = ARRAY_SIZE(features_legacy),
        .driver.name =  KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
index b5554f2ebee4eba4f3b42fff8601f7cae56f8cab..ef83ae3b0a44a4c854c02a5a66e048203ee7ce8e 100644 (file)
@@ -2279,6 +2279,7 @@ vmxnet3_set_mc(struct net_device *netdev)
                                        &adapter->shared->devRead.rxFilterConf;
        u8 *new_table = NULL;
        dma_addr_t new_table_pa = 0;
+       bool new_table_pa_valid = false;
        u32 new_mode = VMXNET3_RXM_UCAST;
 
        if (netdev->flags & IFF_PROMISC) {
@@ -2307,13 +2308,15 @@ vmxnet3_set_mc(struct net_device *netdev)
                                                        new_table,
                                                        sz,
                                                        PCI_DMA_TODEVICE);
+                               if (!dma_mapping_error(&adapter->pdev->dev,
+                                                      new_table_pa)) {
+                                       new_mode |= VMXNET3_RXM_MCAST;
+                                       new_table_pa_valid = true;
+                                       rxConf->mfTablePA = cpu_to_le64(
+                                                               new_table_pa);
+                               }
                        }
-
-                       if (!dma_mapping_error(&adapter->pdev->dev,
-                                              new_table_pa)) {
-                               new_mode |= VMXNET3_RXM_MCAST;
-                               rxConf->mfTablePA = cpu_to_le64(new_table_pa);
-                       } else {
+                       if (!new_table_pa_valid) {
                                netdev_info(netdev,
                                            "failed to copy mcast list, setting ALL_MULTI\n");
                                new_mode |= VMXNET3_RXM_ALL_MULTI;
@@ -2338,7 +2341,7 @@ vmxnet3_set_mc(struct net_device *netdev)
                               VMXNET3_CMD_UPDATE_MAC_FILTERS);
        spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
-       if (new_table_pa)
+       if (new_table_pa_valid)
                dma_unmap_single(&adapter->pdev->dev, new_table_pa,
                                 rxConf->mfTableLen, PCI_DMA_TODEVICE);
        kfree(new_table);
index 85c271c70d42fd57983f9fba822fb93d097d4590..820de6a9ddde1dcfa8ee389bc20e56ae61afa1b9 100644 (file)
@@ -956,6 +956,7 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
        if (skb->pkt_type == PACKET_LOOPBACK) {
                skb->dev = vrf_dev;
                skb->skb_iif = vrf_dev->ifindex;
+               IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
                skb->pkt_type = PACKET_HOST;
                goto out;
        }
@@ -996,6 +997,7 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev,
 {
        skb->dev = vrf_dev;
        skb->skb_iif = vrf_dev->ifindex;
+       IPCB(skb)->flags |= IPSKB_L3SLAVE;
 
        /* loopback traffic; do not push through packet taps again.
         * Reset pkt_type for upper layers to process skb
index e7d16687538b8478fda533e2ceaccdcb83961405..2ba01ca02c9c5ed7f8024cbe7370127a3cb33a4c 100644 (file)
@@ -583,7 +583,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk,
                }
        }
 
-       pp = eth_gro_receive(head, skb);
+       pp = call_gro_receive(eth_gro_receive, head, skb);
        flush = 0;
 
 out:
@@ -611,6 +611,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
        struct vxlan_rdst *rd = NULL;
        struct vxlan_fdb *f;
        int notify = 0;
+       int rc;
 
        f = __vxlan_find_mac(vxlan, mac);
        if (f) {
@@ -641,8 +642,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                if ((flags & NLM_F_APPEND) &&
                    (is_multicast_ether_addr(f->eth_addr) ||
                     is_zero_ether_addr(f->eth_addr))) {
-                       int rc = vxlan_fdb_append(f, ip, port, vni, ifindex,
-                                                 &rd);
+                       rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
 
                        if (rc < 0)
                                return rc;
@@ -673,7 +673,11 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                INIT_LIST_HEAD(&f->remotes);
                memcpy(f->eth_addr, mac, ETH_ALEN);
 
-               vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
+               rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
+               if (rc < 0) {
+                       kfree(f);
+                       return rc;
+               }
 
                ++vxlan->addrcnt;
                hlist_add_head_rcu(&f->hlist,
@@ -943,17 +947,22 @@ static bool vxlan_snoop(struct net_device *dev,
 static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev)
 {
        struct vxlan_dev *vxlan;
+       struct vxlan_sock *sock4;
+#if IS_ENABLED(CONFIG_IPV6)
+       struct vxlan_sock *sock6;
+#endif
        unsigned short family = dev->default_dst.remote_ip.sa.sa_family;
 
+       sock4 = rtnl_dereference(dev->vn4_sock);
+
        /* The vxlan_sock is only used by dev, leaving group has
         * no effect on other vxlan devices.
         */
-       if (family == AF_INET && dev->vn4_sock &&
-           atomic_read(&dev->vn4_sock->refcnt) == 1)
+       if (family == AF_INET && sock4 && atomic_read(&sock4->refcnt) == 1)
                return false;
 #if IS_ENABLED(CONFIG_IPV6)
-       if (family == AF_INET6 && dev->vn6_sock &&
-           atomic_read(&dev->vn6_sock->refcnt) == 1)
+       sock6 = rtnl_dereference(dev->vn6_sock);
+       if (family == AF_INET6 && sock6 && atomic_read(&sock6->refcnt) == 1)
                return false;
 #endif
 
@@ -961,10 +970,12 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev)
                if (!netif_running(vxlan->dev) || vxlan == dev)
                        continue;
 
-               if (family == AF_INET && vxlan->vn4_sock != dev->vn4_sock)
+               if (family == AF_INET &&
+                   rtnl_dereference(vxlan->vn4_sock) != sock4)
                        continue;
 #if IS_ENABLED(CONFIG_IPV6)
-               if (family == AF_INET6 && vxlan->vn6_sock != dev->vn6_sock)
+               if (family == AF_INET6 &&
+                   rtnl_dereference(vxlan->vn6_sock) != sock6)
                        continue;
 #endif
 
@@ -1005,22 +1016,25 @@ static bool __vxlan_sock_release_prep(struct vxlan_sock *vs)
 
 static void vxlan_sock_release(struct vxlan_dev *vxlan)
 {
-       bool ipv4 = __vxlan_sock_release_prep(vxlan->vn4_sock);
+       struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
 #if IS_ENABLED(CONFIG_IPV6)
-       bool ipv6 = __vxlan_sock_release_prep(vxlan->vn6_sock);
+       struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
+
+       rcu_assign_pointer(vxlan->vn6_sock, NULL);
 #endif
 
+       rcu_assign_pointer(vxlan->vn4_sock, NULL);
        synchronize_net();
 
-       if (ipv4) {
-               udp_tunnel_sock_release(vxlan->vn4_sock->sock);
-               kfree(vxlan->vn4_sock);
+       if (__vxlan_sock_release_prep(sock4)) {
+               udp_tunnel_sock_release(sock4->sock);
+               kfree(sock4);
        }
 
 #if IS_ENABLED(CONFIG_IPV6)
-       if (ipv6) {
-               udp_tunnel_sock_release(vxlan->vn6_sock->sock);
-               kfree(vxlan->vn6_sock);
+       if (__vxlan_sock_release_prep(sock6)) {
+               udp_tunnel_sock_release(sock6->sock);
+               kfree(sock6);
        }
 #endif
 }
@@ -1036,18 +1050,21 @@ static int vxlan_igmp_join(struct vxlan_dev *vxlan)
        int ret = -EINVAL;
 
        if (ip->sa.sa_family == AF_INET) {
+               struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
                struct ip_mreqn mreq = {
                        .imr_multiaddr.s_addr   = ip->sin.sin_addr.s_addr,
                        .imr_ifindex            = ifindex,
                };
 
-               sk = vxlan->vn4_sock->sock->sk;
+               sk = sock4->sock->sk;
                lock_sock(sk);
                ret = ip_mc_join_group(sk, &mreq);
                release_sock(sk);
 #if IS_ENABLED(CONFIG_IPV6)
        } else {
-               sk = vxlan->vn6_sock->sock->sk;
+               struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
+
+               sk = sock6->sock->sk;
                lock_sock(sk);
                ret = ipv6_stub->ipv6_sock_mc_join(sk, ifindex,
                                                   &ip->sin6.sin6_addr);
@@ -1067,18 +1084,21 @@ static int vxlan_igmp_leave(struct vxlan_dev *vxlan)
        int ret = -EINVAL;
 
        if (ip->sa.sa_family == AF_INET) {
+               struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
                struct ip_mreqn mreq = {
                        .imr_multiaddr.s_addr   = ip->sin.sin_addr.s_addr,
                        .imr_ifindex            = ifindex,
                };
 
-               sk = vxlan->vn4_sock->sock->sk;
+               sk = sock4->sock->sk;
                lock_sock(sk);
                ret = ip_mc_leave_group(sk, &mreq);
                release_sock(sk);
 #if IS_ENABLED(CONFIG_IPV6)
        } else {
-               sk = vxlan->vn6_sock->sock->sk;
+               struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
+
+               sk = sock6->sock->sk;
                lock_sock(sk);
                ret = ipv6_stub->ipv6_sock_mc_drop(sk, ifindex,
                                                   &ip->sin6.sin6_addr);
@@ -1828,11 +1848,15 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
                                          struct dst_cache *dst_cache,
                                          const struct ip_tunnel_info *info)
 {
+       struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
        bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct dst_entry *ndst;
        struct flowi6 fl6;
        int err;
 
+       if (!sock6)
+               return ERR_PTR(-EIO);
+
        if (tos && !info)
                use_cache = false;
        if (use_cache) {
@@ -1850,7 +1874,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
        fl6.flowi6_proto = IPPROTO_UDP;
 
        err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
-                                        vxlan->vn6_sock->sock->sk,
+                                        sock6->sock->sk,
                                         &ndst, &fl6);
        if (err < 0)
                return ERR_PTR(err);
@@ -1995,9 +2019,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
        }
 
        if (dst->sa.sa_family == AF_INET) {
-               if (!vxlan->vn4_sock)
+               struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
+
+               if (!sock4)
                        goto drop;
-               sk = vxlan->vn4_sock->sock->sk;
+               sk = sock4->sock->sk;
 
                rt = vxlan_get_route(vxlan, skb,
                                     rdst ? rdst->remote_ifindex : 0, tos,
@@ -2050,12 +2076,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                                    src_port, dst_port, xnet, !udp_sum);
 #if IS_ENABLED(CONFIG_IPV6)
        } else {
+               struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
                struct dst_entry *ndst;
                u32 rt6i_flags;
 
-               if (!vxlan->vn6_sock)
+               if (!sock6)
                        goto drop;
-               sk = vxlan->vn6_sock->sock->sk;
+               sk = sock6->sock->sk;
 
                ndst = vxlan6_get_route(vxlan, skb,
                                        rdst ? rdst->remote_ifindex : 0, tos,
@@ -2415,9 +2442,10 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
        dport = info->key.tp_dst ? : vxlan->cfg.dst_port;
 
        if (ip_tunnel_info_af(info) == AF_INET) {
+               struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
                struct rtable *rt;
 
-               if (!vxlan->vn4_sock)
+               if (!sock4)
                        return -EINVAL;
                rt = vxlan_get_route(vxlan, skb, 0, info->key.tos,
                                     info->key.u.ipv4.dst,
@@ -2429,8 +2457,6 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 #if IS_ENABLED(CONFIG_IPV6)
                struct dst_entry *ndst;
 
-               if (!vxlan->vn6_sock)
-                       return -EINVAL;
                ndst = vxlan6_get_route(vxlan, skb, 0, info->key.tos,
                                        info->key.label, &info->key.u.ipv6.dst,
                                        &info->key.u.ipv6.src, NULL, info);
@@ -2740,10 +2766,10 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6)
                return PTR_ERR(vs);
 #if IS_ENABLED(CONFIG_IPV6)
        if (ipv6)
-               vxlan->vn6_sock = vs;
+               rcu_assign_pointer(vxlan->vn6_sock, vs);
        else
 #endif
-               vxlan->vn4_sock = vs;
+               rcu_assign_pointer(vxlan->vn4_sock, vs);
        vxlan_vs_add_dev(vs, vxlan);
        return 0;
 }
@@ -2754,9 +2780,9 @@ static int vxlan_sock_add(struct vxlan_dev *vxlan)
        bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA;
        int ret = 0;
 
-       vxlan->vn4_sock = NULL;
+       RCU_INIT_POINTER(vxlan->vn4_sock, NULL);
 #if IS_ENABLED(CONFIG_IPV6)
-       vxlan->vn6_sock = NULL;
+       RCU_INIT_POINTER(vxlan->vn6_sock, NULL);
        if (ipv6 || metadata)
                ret = __vxlan_sock_add(vxlan, true);
 #endif
index 33ab3345d333b68f983b61152d074e20f16e5e1e..4e9fe75d70675d052ad2f2be3f513b5c20dfef9a 100644 (file)
@@ -294,7 +294,7 @@ config FSL_UCC_HDLC
 config SLIC_DS26522
        tristate "Slic Maxim ds26522 card support"
        depends on SPI
-       depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE
+       depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST
        help
          This module initializes and configures the slic maxim card
          in T1 or E1 mode.
index d06a887a2352141bfb0e72c46e37ad6a28f6a1de..b776a0ab106c0d55b1b7cdf14b79d91621d27aa1 100644 (file)
@@ -223,12 +223,19 @@ static int slic_ds26522_probe(struct spi_device *spi)
        return ret;
 }
 
+static const struct spi_device_id slic_ds26522_id[] = {
+       { .name = "ds26522" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(spi, slic_ds26522_id);
+
 static const struct of_device_id slic_ds26522_match[] = {
        {
         .compatible = "maxim,ds26522",
         },
        {},
 };
+MODULE_DEVICE_TABLE(of, slic_ds26522_match);
 
 static struct spi_driver slic_ds26522_driver = {
        .driver = {
@@ -239,6 +246,7 @@ static struct spi_driver slic_ds26522_driver = {
                   },
        .probe = slic_ds26522_probe,
        .remove = slic_ds26522_remove,
+       .id_table = slic_ds26522_id,
 };
 
 static int __init slic_ds26522_init(void)
index dda49af1eb744a443f9bb8eb4107e7cde1c2a882..521f1c55c19ee150e99403b8238cb54f065fc673 100644 (file)
@@ -450,6 +450,7 @@ struct ath10k_debug {
        u32 pktlog_filter;
        u32 reg_addr;
        u32 nf_cal_period;
+       void *cal_data;
 
        struct ath10k_fw_crash_data *fw_crash_data;
 };
index 832da6ed9f13c002ca0c597793c6da618b6c29d1..82a4c67f3672ba8e7f05951ee3dd6916ac1ca356 100644 (file)
@@ -30,6 +30,8 @@
 /* ms */
 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
 
+#define ATH10K_DEBUG_CAL_DATA_LEN 12064
+
 #define ATH10K_FW_CRASH_DUMP_VERSION 1
 
 /**
@@ -1451,56 +1453,51 @@ static const struct file_operations fops_fw_dbglog = {
        .llseek = default_llseek,
 };
 
-static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
+static int ath10k_debug_cal_data_fetch(struct ath10k *ar)
 {
-       struct ath10k *ar = inode->i_private;
-       void *buf;
        u32 hi_addr;
        __le32 addr;
        int ret;
 
-       mutex_lock(&ar->conf_mutex);
-
-       if (ar->state != ATH10K_STATE_ON &&
-           ar->state != ATH10K_STATE_UTF) {
-               ret = -ENETDOWN;
-               goto err;
-       }
+       lockdep_assert_held(&ar->conf_mutex);
 
-       buf = vmalloc(ar->hw_params.cal_data_len);
-       if (!buf) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN))
+               return -EINVAL;
 
        hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
 
        ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
        if (ret) {
-               ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret);
-               goto err_vfree;
+               ath10k_warn(ar, "failed to read hi_board_data address: %d\n",
+                           ret);
+               return ret;
        }
 
-       ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf,
+       ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data,
                                   ar->hw_params.cal_data_len);
        if (ret) {
                ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
-               goto err_vfree;
+               return ret;
        }
 
-       file->private_data = buf;
+       return 0;
+}
 
-       mutex_unlock(&ar->conf_mutex);
+static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
+{
+       struct ath10k *ar = inode->i_private;
 
-       return 0;
+       mutex_lock(&ar->conf_mutex);
 
-err_vfree:
-       vfree(buf);
+       if (ar->state == ATH10K_STATE_ON ||
+           ar->state == ATH10K_STATE_UTF) {
+               ath10k_debug_cal_data_fetch(ar);
+       }
 
-err:
+       file->private_data = ar;
        mutex_unlock(&ar->conf_mutex);
 
-       return ret;
+       return 0;
 }
 
 static ssize_t ath10k_debug_cal_data_read(struct file *file,
@@ -1508,18 +1505,16 @@ static ssize_t ath10k_debug_cal_data_read(struct file *file,
                                          size_t count, loff_t *ppos)
 {
        struct ath10k *ar = file->private_data;
-       void *buf = file->private_data;
 
-       return simple_read_from_buffer(user_buf, count, ppos,
-                                      buf, ar->hw_params.cal_data_len);
-}
+       mutex_lock(&ar->conf_mutex);
 
-static int ath10k_debug_cal_data_release(struct inode *inode,
-                                        struct file *file)
-{
-       vfree(file->private_data);
+       count = simple_read_from_buffer(user_buf, count, ppos,
+                                       ar->debug.cal_data,
+                                       ar->hw_params.cal_data_len);
 
-       return 0;
+       mutex_unlock(&ar->conf_mutex);
+
+       return count;
 }
 
 static ssize_t ath10k_write_ani_enable(struct file *file,
@@ -1580,7 +1575,6 @@ static const struct file_operations fops_ani_enable = {
 static const struct file_operations fops_cal_data = {
        .open = ath10k_debug_cal_data_open,
        .read = ath10k_debug_cal_data_read,
-       .release = ath10k_debug_cal_data_release,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
 };
@@ -1932,6 +1926,8 @@ void ath10k_debug_stop(struct ath10k *ar)
 {
        lockdep_assert_held(&ar->conf_mutex);
 
+       ath10k_debug_cal_data_fetch(ar);
+
        /* Must not use _sync to avoid deadlock, we do that in
         * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
         * warning from del_timer(). */
@@ -2344,6 +2340,10 @@ int ath10k_debug_create(struct ath10k *ar)
        if (!ar->debug.fw_crash_data)
                return -ENOMEM;
 
+       ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
+       if (!ar->debug.cal_data)
+               return -ENOMEM;
+
        INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
        INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
        INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
@@ -2357,6 +2357,9 @@ void ath10k_debug_destroy(struct ath10k *ar)
        vfree(ar->debug.fw_crash_data);
        ar->debug.fw_crash_data = NULL;
 
+       vfree(ar->debug.cal_data);
+       ar->debug.cal_data = NULL;
+
        ath10k_debug_fw_stats_reset(ar);
 
        kfree(ar->debug.tpc_stats);
index eab0ab976af29ebb0b355f82b01caeb39bd07152..76eb33679d4bd85c8abb50a9af60cbfa4b4ddb14 100644 (file)
@@ -1401,6 +1401,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))},
+       {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x18))},
        {},
 };
 
index b6f064a8d2645204725670f23aabe45d810ff431..7e27a06e5df197cbf5e5a41b97e61723d38d72a8 100644 (file)
@@ -33,7 +33,6 @@ struct coeff {
 
 enum ar9003_cal_types {
        IQ_MISMATCH_CAL = BIT(0),
-       TEMP_COMP_CAL = BIT(1),
 };
 
 static void ar9003_hw_setup_calibration(struct ath_hw *ah,
@@ -59,12 +58,6 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
                /* Kick-off cal */
                REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
                break;
-       case TEMP_COMP_CAL:
-               ath_dbg(common, CALIBRATE,
-                       "starting Temperature Compensation Calibration\n");
-               REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL);
-               REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START);
-               break;
        default:
                ath_err(common, "Invalid calibration type\n");
                break;
@@ -93,8 +86,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
                /*
                * Accumulate cal measures for active chains
                */
-               if (cur_caldata->calCollect)
-                       cur_caldata->calCollect(ah);
+               cur_caldata->calCollect(ah);
                ah->cal_samples++;
 
                if (ah->cal_samples >= cur_caldata->calNumSamples) {
@@ -107,8 +99,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
                        /*
                        * Process accumulated data
                        */
-                       if (cur_caldata->calPostProc)
-                               cur_caldata->calPostProc(ah, numChains);
+                       cur_caldata->calPostProc(ah, numChains);
 
                        /* Calibration has finished. */
                        caldata->CalValid |= cur_caldata->calType;
@@ -323,16 +314,9 @@ static const struct ath9k_percal_data iq_cal_single_sample = {
        ar9003_hw_iqcalibrate
 };
 
-static const struct ath9k_percal_data temp_cal_single_sample = {
-       TEMP_COMP_CAL,
-       MIN_CAL_SAMPLES,
-       PER_MAX_LOG_COUNT,
-};
-
 static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
 {
        ah->iq_caldata.calData = &iq_cal_single_sample;
-       ah->temp_caldata.calData = &temp_cal_single_sample;
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ah->enabled_cals |= TX_IQ_CAL;
@@ -340,7 +324,7 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
                        ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
        }
 
-       ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL;
+       ah->supp_cals = IQ_MISMATCH_CAL;
 }
 
 #define OFF_UPPER_LT 24
@@ -1399,9 +1383,6 @@ static void ar9003_hw_init_cal_common(struct ath_hw *ah)
        INIT_CAL(&ah->iq_caldata);
        INSERT_CAL(ah, &ah->iq_caldata);
 
-       INIT_CAL(&ah->temp_caldata);
-       INSERT_CAL(ah, &ah->temp_caldata);
-
        /* Initialize current pointer to first element in list */
        ah->cal_list_curr = ah->cal_list;
 
index 2a5d3ad1169c955ed781a95a353e542d1dcc571b..9cbca1229bac02862211c14d14048f08197dd39d 100644 (file)
@@ -830,7 +830,6 @@ struct ath_hw {
        /* Calibration */
        u32 supp_cals;
        struct ath9k_cal_list iq_caldata;
-       struct ath9k_cal_list temp_caldata;
        struct ath9k_cal_list adcgain_caldata;
        struct ath9k_cal_list adcdc_caldata;
        struct ath9k_cal_list *cal_list;
index b777e1b2f87aeb06d6c1b527b1b92aee744dd2e1..78d9966a3957b2b934fe6b21de5cade494ec2839 100644 (file)
@@ -4516,7 +4516,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        /* store current 11d setting */
        if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
                                  &ifp->vif->is_11d)) {
-               supports_11d = false;
+               is_11d = supports_11d = false;
        } else {
                country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
                                              settings->beacon.tail_len,
index 4fdc3dad3e85437492efc25df76b8ce8a02ad0ec..b88e2048ae0baa207406972c618a28c7db4026e4 100644 (file)
@@ -1087,6 +1087,15 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
                ret = iwl_mvm_switch_to_d3(mvm);
                if (ret)
                        return ret;
+       } else {
+               /* In theory, we wouldn't have to stop a running sched
+                * scan in order to start another one (for
+                * net-detect).  But in practice this doesn't seem to
+                * work properly, so stop any running sched_scan now.
+                */
+               ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
+               if (ret)
+                       return ret;
        }
 
        /* rfkill release can be either for wowlan or netdetect */
@@ -1254,7 +1263,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
  out:
        if (ret < 0) {
                iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
-               ieee80211_restart_hw(mvm->hw);
+               if (mvm->restart_fw > 0) {
+                       mvm->restart_fw--;
+                       ieee80211_restart_hw(mvm->hw);
+               }
                iwl_mvm_free_nd(mvm);
        }
  out_noreset:
@@ -2088,6 +2100,16 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        iwl_mvm_update_changed_regdom(mvm);
 
        if (mvm->net_detect) {
+               /* If this is a non-unified image, we restart the FW,
+                * so no need to stop the netdetect scan.  If that
+                * fails, continue and try to get the wake-up reasons,
+                * but trigger a HW restart by keeping a failure code
+                * in ret.
+                */
+               if (unified_image)
+                       ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_NETDETECT,
+                                               false);
+
                iwl_mvm_query_netdetect_reasons(mvm, vif);
                /* has unlocked the mutex, so skip that */
                goto out;
@@ -2271,7 +2293,8 @@ static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,
 static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
 {
        struct iwl_mvm *mvm = inode->i_private;
-       int remaining_time = 10;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
        mvm->d3_test_active = false;
 
@@ -2282,17 +2305,21 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
        mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
 
        iwl_abort_notification_waits(&mvm->notif_wait);
-       ieee80211_restart_hw(mvm->hw);
+       if (!unified_image) {
+               int remaining_time = 10;
 
-       /* wait for restart and disconnect all interfaces */
-       while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
-              remaining_time > 0) {
-               remaining_time--;
-               msleep(1000);
-       }
+               ieee80211_restart_hw(mvm->hw);
+
+               /* wait for restart and disconnect all interfaces */
+               while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+                      remaining_time > 0) {
+                       remaining_time--;
+                       msleep(1000);
+               }
 
-       if (remaining_time == 0)
-               IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n");
+               if (remaining_time == 0)
+                       IWL_ERR(mvm, "Timed out waiting for HW restart!\n");
+       }
 
        ieee80211_iterate_active_interfaces_atomic(
                mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
index 07da4efe8458f8a38b5ccf315d29e2427a3d0a35..7b7d2a146e3020a286da8f7acc9a97d005142ce8 100644 (file)
@@ -1529,8 +1529,8 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
                .data = { &cmd, },
                .len = { sizeof(cmd) },
        };
-       size_t delta, len;
-       ssize_t ret;
+       size_t delta;
+       ssize_t ret, len;
 
        hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
                             DEBUG_GROUP, 0);
index 318efd8140375c1ff26e6387b225bea2f3fbe6e2..1db1dc13e988a93e71cbc18c02dc8ee3174b9905 100644 (file)
@@ -4121,7 +4121,6 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
                                     struct iwl_mvm_internal_rxq_notif *notif,
                                     u32 size)
 {
-       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq);
        u32 qmask = BIT(mvm->trans->num_rx_queues) - 1;
        int ret;
 
@@ -4143,7 +4142,7 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
        }
 
        if (notif->sync)
-               ret = wait_event_timeout(notif_waitq,
+               ret = wait_event_timeout(mvm->rx_sync_waitq,
                                         atomic_read(&mvm->queue_sync_counter) == 0,
                                         HZ);
        WARN_ON_ONCE(!ret);
index d17cbf603f7c7b488e6a7be366a5aeed6f9f4775..c60703e0c246731cc3976dbe03f1f6fabe76f028 100644 (file)
@@ -937,6 +937,7 @@ struct iwl_mvm {
        /* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */
        spinlock_t d0i3_tx_lock;
        wait_queue_head_t d0i3_exit_waitq;
+       wait_queue_head_t rx_sync_waitq;
 
        /* BT-Coex */
        struct iwl_bt_coex_profile_notif last_bt_notif;
index 05fe6dd1a2c81652330aec05f743f50bae59bca5..4d35deb628bcaae711851a7e4acaf158883b57f0 100644 (file)
@@ -619,6 +619,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        spin_lock_init(&mvm->refs_lock);
        skb_queue_head_init(&mvm->d0i3_tx);
        init_waitqueue_head(&mvm->d0i3_exit_waitq);
+       init_waitqueue_head(&mvm->rx_sync_waitq);
 
        atomic_set(&mvm->queue_sync_counter, 0);
 
index a57c6ef5bc14f4cd7dd61df53682b18a9c6f7d3a..6c802cee900c925a7734e6a8f461a24f71c5ede6 100644 (file)
@@ -547,7 +547,8 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                                  "Received expired RX queue sync message\n");
                        return;
                }
-               atomic_dec(&mvm->queue_sync_counter);
+               if (!atomic_dec_return(&mvm->queue_sync_counter))
+                       wake_up(&mvm->rx_sync_waitq);
        }
 
        switch (internal_notif->type) {
index f279fdd6eb441f1a671d312a9f76b8eca1deae72..fa97432054912b53493d6e0f75000c6def479d93 100644 (file)
@@ -1199,6 +1199,9 @@ static int iwl_mvm_num_scans(struct iwl_mvm *mvm)
 
 static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
 {
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
+
        /* This looks a bit arbitrary, but the idea is that if we run
         * out of possible simultaneous scans and the userspace is
         * trying to run a scan type that is already running, we
@@ -1225,12 +1228,30 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
                        return -EBUSY;
                return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
        case IWL_MVM_SCAN_NETDETECT:
-               /* No need to stop anything for net-detect since the
-                * firmware is restarted anyway.  This way, any sched
-                * scans that were running will be restarted when we
-                * resume.
-               */
-               return 0;
+               /* For non-unified images, there's no need to stop
+                * anything for net-detect since the firmware is
+                * restarted anyway.  This way, any sched scans that
+                * were running will be restarted when we resume.
+                */
+               if (!unified_image)
+                       return 0;
+
+               /* If this is a unified image and we ran out of scans,
+                * we need to stop something.  Prefer stopping regular
+                * scans, because the results are useless at this
+                * point, and we should be able to keep running
+                * another scheduled scan while suspended.
+                */
+               if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK)
+                       return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR,
+                                                true);
+               if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK)
+                       return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED,
+                                                true);
+
+               /* fall through, something is wrong if no scan was
+                * running but we ran out of scans.
+                */
        default:
                WARN_ON(1);
                break;
index 001be406a3d3852a7c735f1207a134a563c1784a..2f8134b2a504223856b02692eb5ff8f6a7f4acd8 100644 (file)
@@ -541,48 +541,64 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
 
 #ifdef CONFIG_ACPI
-#define SPL_METHOD             "SPLC"
-#define SPL_DOMAINTYPE_MODULE  BIT(0)
-#define SPL_DOMAINTYPE_WIFI    BIT(1)
-#define SPL_DOMAINTYPE_WIGIG   BIT(2)
-#define SPL_DOMAINTYPE_RFEM    BIT(3)
+#define ACPI_SPLC_METHOD       "SPLC"
+#define ACPI_SPLC_DOMAIN_WIFI  (0x07)
 
-static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx)
+static u64 splc_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splc)
 {
-       union acpi_object *limits, *domain_type, *power_limit;
-
-       if (splx->type != ACPI_TYPE_PACKAGE ||
-           splx->package.count != 2 ||
-           splx->package.elements[0].type != ACPI_TYPE_INTEGER ||
-           splx->package.elements[0].integer.value != 0) {
-               IWL_ERR(trans, "Unsupported splx structure\n");
+       union acpi_object *data_pkg, *dflt_pwr_limit;
+       int i;
+
+       /* We need at least two elements, one for the revision and one
+        * for the data itself.  Also check that the revision is
+        * supported (currently only revision 0).
+       */
+       if (splc->type != ACPI_TYPE_PACKAGE ||
+           splc->package.count < 2 ||
+           splc->package.elements[0].type != ACPI_TYPE_INTEGER ||
+           splc->package.elements[0].integer.value != 0) {
+               IWL_DEBUG_INFO(trans,
+                              "Unsupported structure returned by the SPLC method.  Ignoring.\n");
                return 0;
        }
 
-       limits = &splx->package.elements[1];
-       if (limits->type != ACPI_TYPE_PACKAGE ||
-           limits->package.count < 2 ||
-           limits->package.elements[0].type != ACPI_TYPE_INTEGER ||
-           limits->package.elements[1].type != ACPI_TYPE_INTEGER) {
-               IWL_ERR(trans, "Invalid limits element\n");
-               return 0;
+       /* loop through all the packages to find the one for WiFi */
+       for (i = 1; i < splc->package.count; i++) {
+               union acpi_object *domain;
+
+               data_pkg = &splc->package.elements[i];
+
+               /* Skip anything that is not a package with the right
+                * amount of elements (i.e. at least 2 integers).
+                */
+               if (data_pkg->type != ACPI_TYPE_PACKAGE ||
+                   data_pkg->package.count < 2 ||
+                   data_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
+                   data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
+                       continue;
+
+               domain = &data_pkg->package.elements[0];
+               if (domain->integer.value == ACPI_SPLC_DOMAIN_WIFI)
+                       break;
+
+               data_pkg = NULL;
        }
 
-       domain_type = &limits->package.elements[0];
-       power_limit = &limits->package.elements[1];
-       if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) {
-               IWL_DEBUG_INFO(trans, "WiFi power is not limited\n");
+       if (!data_pkg) {
+               IWL_DEBUG_INFO(trans,
+                              "No element for the WiFi domain returned by the SPLC method.\n");
                return 0;
        }
 
-       return power_limit->integer.value;
+       dflt_pwr_limit = &data_pkg->package.elements[1];
+       return dflt_pwr_limit->integer.value;
 }
 
 static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)
 {
        acpi_handle pxsx_handle;
        acpi_handle handle;
-       struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL};
+       struct acpi_buffer splc = {ACPI_ALLOCATE_BUFFER, NULL};
        acpi_status status;
 
        pxsx_handle = ACPI_HANDLE(&pdev->dev);
@@ -593,23 +609,24 @@ static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)
        }
 
        /* Get the method's handle */
-       status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle);
+       status = acpi_get_handle(pxsx_handle, (acpi_string)ACPI_SPLC_METHOD,
+                                &handle);
        if (ACPI_FAILURE(status)) {
-               IWL_DEBUG_INFO(trans, "SPL method not found\n");
+               IWL_DEBUG_INFO(trans, "SPLC method not found\n");
                return;
        }
 
        /* Call SPLC with no arguments */
-       status = acpi_evaluate_object(handle, NULL, NULL, &splx);
+       status = acpi_evaluate_object(handle, NULL, NULL, &splc);
        if (ACPI_FAILURE(status)) {
                IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status);
                return;
        }
 
-       trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer);
+       trans->dflt_pwr_limit = splc_get_pwr_limit(trans, splc.pointer);
        IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n",
                       trans->dflt_pwr_limit);
-       kfree(splx.pointer);
+       kfree(splc.pointer);
 }
 
 #else /* CONFIG_ACPI */
index e9a278b60dfd87996318cd0096f78486c3d7b855..5f840f16f40bd955478196397f8dcff481e88077 100644 (file)
@@ -592,6 +592,7 @@ error:
 static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
                              int slots_num, u32 txq_id)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
 
        txq->need_update = false;
@@ -606,6 +607,13 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
                return ret;
 
        spin_lock_init(&txq->lock);
+
+       if (txq_id == trans_pcie->cmd_queue) {
+               static struct lock_class_key iwl_pcie_cmd_queue_lock_class;
+
+               lockdep_set_class(&txq->lock, &iwl_pcie_cmd_queue_lock_class);
+       }
+
        __skb_queue_head_init(&txq->overflow_q);
 
        /*
index 431f13b4faf690c885fbd459b257de5d103406a8..d3bad577937622c868257892cf1658c561c3b947 100644 (file)
@@ -826,7 +826,7 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
                data->bcn_delta = do_div(delta, bcn_int);
        } else {
                data->tsf_offset -= delta;
-               data->bcn_delta = -do_div(delta, bcn_int);
+               data->bcn_delta = -(s64)do_div(delta, bcn_int);
        }
 }
 
index 94480123efa3d967dbe08dfa10114218343c4df5..274dd5a1574a3f4a936637b60f6f78fca645bdbc 100644 (file)
@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
                skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
 
                ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
-                                        priv->wdev.iftype, 0, false);
+                                        priv->wdev.iftype, 0, NULL, NULL);
 
                while (!skb_queue_empty(&list)) {
                        struct rx_packet_hdr *rx_hdr;
index 39ce76ad00bc052d9dc99d5f1162842dc2dc2f3a..16241d21727bf35214ae41424d6b201520471ef2 100644 (file)
@@ -2222,8 +2222,9 @@ done:
                        is_scanning_required = 1;
                } else {
                        mwifiex_dbg(priv->adapter, MSG,
-                                   "info: trying to associate to '%s' bssid %pM\n",
-                                   (char *)req_ssid.ssid, bss->bssid);
+                                   "info: trying to associate to '%.*s' bssid %pM\n",
+                                   req_ssid.ssid_len, (char *)req_ssid.ssid,
+                                   bss->bssid);
                        memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN);
                        break;
                }
@@ -2283,8 +2284,8 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        }
 
        mwifiex_dbg(adapter, INFO,
-                   "info: Trying to associate to %s and bssid %pM\n",
-                   (char *)sme->ssid, sme->bssid);
+                   "info: Trying to associate to %.*s and bssid %pM\n",
+                   (int)sme->ssid_len, (char *)sme->ssid, sme->bssid);
 
        if (!mwifiex_stop_bg_scan(priv))
                cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
@@ -2417,8 +2418,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
        }
 
        mwifiex_dbg(priv->adapter, MSG,
-                   "info: trying to join to %s and bssid %pM\n",
-                   (char *)params->ssid, params->bssid);
+                   "info: trying to join to %.*s and bssid %pM\n",
+                   params->ssid_len, (char *)params->ssid, params->bssid);
 
        mwifiex_set_ibss_params(priv, params);
 
index 1016628926d22ea39858457ed1cf369d825f8875..08d587a342d32c8e2111e10955519009d9718ca6 100644 (file)
@@ -238,7 +238,7 @@ struct rtl8xxxu_rxdesc16 {
        u32 pattern1match:1;
        u32 pattern0match:1;
 #endif
-       __le32 tsfl;
+       u32 tsfl;
 #if 0
        u32 bassn:12;
        u32 bavld:1;
@@ -368,7 +368,7 @@ struct rtl8xxxu_rxdesc24 {
        u32 ldcp:1;
        u32 splcp:1;
 #endif
-       __le32 tsfl;
+       u32 tsfl;
 };
 
 struct rtl8xxxu_txdesc32 {
index df54d27e78516110f6045d2853d794b770b98e4f..a793fedc3654626ece17de0eaec4dab57a2872eb 100644 (file)
@@ -1461,7 +1461,9 @@ static int rtl8192eu_active_to_emu(struct rtl8xxxu_priv *priv)
        int count, ret = 0;
 
        /* Turn off RF */
-       rtl8xxxu_write8(priv, REG_RF_CTRL, 0);
+       val8 = rtl8xxxu_read8(priv, REG_RF_CTRL);
+       val8 &= ~RF_ENABLE;
+       rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
 
        /* Switch DPDT_SEL_P output from register 0x65[2] */
        val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
@@ -1593,6 +1595,10 @@ static void rtl8192e_enable_rf(struct rtl8xxxu_priv *priv)
        u32 val32;
        u8 val8;
 
+       val32 = rtl8xxxu_read32(priv, REG_RX_WAIT_CCA);
+       val32 |= (BIT(22) | BIT(23));
+       rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, val32);
+
        val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG);
        val8 |= BIT(5);
        rtl8xxxu_write8(priv, REG_GPIO_MUXCFG, val8);
index 6c086b5657e94845b4362860620185828d7c3e2c..02b8ddd98a95d207323dcac13d514c0b987c5afe 100644 (file)
@@ -1498,6 +1498,10 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv)
        u32 val32;
        u8 val8;
 
+       val32 = rtl8xxxu_read32(priv, REG_RX_WAIT_CCA);
+       val32 |= (BIT(22) | BIT(23));
+       rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, val32);
+
        /*
         * No indication anywhere as to what 0x0790 does. The 2 antenna
         * vendor code preserves bits 6-7 here.
index b2d7f6e696675619fffe8eb358de18a93b69a89f..a5e6ec2152bff8808b38bd8f96dfe0ff37a19918 100644 (file)
@@ -5197,7 +5197,12 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
                pkt_offset = roundup(pkt_len + drvinfo_sz + desc_shift +
                                     sizeof(struct rtl8xxxu_rxdesc16), 128);
 
-               if (pkt_cnt > 1)
+               /*
+                * Only clone the skb if there's enough data at the end to
+                * at least cover the rx descriptor
+                */
+               if (pkt_cnt > 1 &&
+                   urb_len > (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16)))
                        next_skb = skb_clone(skb, GFP_ATOMIC);
 
                rx_status = IEEE80211_SKB_RXCB(skb);
@@ -5215,7 +5220,7 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
                        rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats,
                                                   rx_desc->rxmcs);
 
-               rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
+               rx_status->mactime = rx_desc->tsfl;
                rx_status->flag |= RX_FLAG_MACTIME_START;
 
                if (!rx_desc->swdec)
@@ -5285,7 +5290,7 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
                rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats,
                                           rx_desc->rxmcs);
 
-       rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
+       rx_status->mactime = rx_desc->tsfl;
        rx_status->flag |= RX_FLAG_MACTIME_START;
 
        if (!rx_desc->swdec)
index f95760c13c56eeee19229c375cc54be371f461bf..8e7f23c11680a5fa98352e5052f02fa9ae091de8 100644 (file)
@@ -111,7 +111,7 @@ static void rtl_fw_do_work(const struct firmware *firmware, void *context,
                        if (!err)
                                goto found_alt;
                }
-               pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
+               pr_err("Selected firmware is not available\n");
                rtlpriv->max_fw_size = 0;
                return;
        }
index e7b11b40e68dc3e4e8925fb8e80551527124f3a5..f361808def47af36272213111413748546783b76 100644 (file)
@@ -86,6 +86,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        u8 tid;
+       char *fw_name;
 
        rtl8188ee_bt_reg_init(hw);
        rtlpriv->dm.dm_initialgain_enable = 1;
@@ -169,10 +170,10 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
                return 1;
        }
 
-       rtlpriv->cfg->fw_name = "rtlwifi/rtl8188efw.bin";
+       fw_name = "rtlwifi/rtl8188efw.bin";
        rtlpriv->max_fw_size = 0x8000;
-       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       pr_info("Using firmware %s\n", fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_fw_cb);
        if (err) {
@@ -284,7 +285,6 @@ static const struct rtl_hal_cfg rtl88ee_hal_cfg = {
        .bar_id = 2,
        .write_readback = true,
        .name = "rtl88e_pci",
-       .fw_name = "rtlwifi/rtl8188efw.bin",
        .ops = &rtl8188ee_hal_ops,
        .mod_params = &rtl88ee_mod_params,
 
index 87aa209ae325d46062dd6dea7905eb664ff0a5ea..8b6e37ce3f6690ae499d88bfef81ca2913ecc48f 100644 (file)
@@ -96,6 +96,7 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       char *fw_name = "rtlwifi/rtl8192cfwU.bin";
 
        rtl8192ce_bt_reg_init(hw);
 
@@ -167,15 +168,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
        }
 
        /* request fw */
-       if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
-           !IS_92C_SERIAL(rtlhal->version))
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin";
-       else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version))
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
+       if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version))
+               fw_name = "rtlwifi/rtl8192cfwU_B.bin";
 
        rtlpriv->max_fw_size = 0x4000;
-       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       pr_info("Using firmware %s\n", fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_fw_cb);
        if (err) {
@@ -262,7 +260,6 @@ static const struct rtl_hal_cfg rtl92ce_hal_cfg = {
        .bar_id = 2,
        .write_readback = true,
        .name = "rtl92c_pci",
-       .fw_name = "rtlwifi/rtl8192cfw.bin",
        .ops = &rtl8192ce_hal_ops,
        .mod_params = &rtl92ce_mod_params,
 
index 7c6f7f0d18c602011d9048fc54565b105efaf64e..f953320f0e23a86661d141a67fe109f29c09a80c 100644 (file)
@@ -59,6 +59,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        int err;
+       char *fw_name;
 
        rtlpriv->dm.dm_initialgain_enable = true;
        rtlpriv->dm.dm_flag = 0;
@@ -77,18 +78,18 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
        }
        if (IS_VENDOR_UMC_A_CUT(rtlpriv->rtlhal.version) &&
            !IS_92C_SERIAL(rtlpriv->rtlhal.version)) {
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_A.bin";
+               fw_name = "rtlwifi/rtl8192cufw_A.bin";
        } else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlpriv->rtlhal.version)) {
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_B.bin";
+               fw_name = "rtlwifi/rtl8192cufw_B.bin";
        } else {
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
+               fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
        }
        /* provide name of alternative file */
        rtlpriv->cfg->alt_fw_name = "rtlwifi/rtl8192cufw.bin";
-       pr_info("Loading firmware %s\n", rtlpriv->cfg->fw_name);
+       pr_info("Loading firmware %s\n", fw_name);
        rtlpriv->max_fw_size = 0x4000;
        err = request_firmware_nowait(THIS_MODULE, 1,
-                                     rtlpriv->cfg->fw_name, rtlpriv->io.dev,
+                                     fw_name, rtlpriv->io.dev,
                                      GFP_KERNEL, hw, rtl_fw_cb);
        return err;
 }
@@ -187,7 +188,6 @@ static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = {
 
 static struct rtl_hal_cfg rtl92cu_hal_cfg = {
        .name = "rtl92c_usb",
-       .fw_name = "rtlwifi/rtl8192cufw.bin",
        .ops = &rtl8192cu_hal_ops,
        .mod_params = &rtl92cu_mod_params,
        .usb_interface_cfg = &rtl92cu_interface_cfg,
index 0538a4d09568850485e334ebfedf752f5f03ce69..1ebfee18882fb4f1bf8cd31ed303bd98e96542ab 100644 (file)
@@ -92,6 +92,7 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
        u8 tid;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       char *fw_name = "rtlwifi/rtl8192defw.bin";
 
        rtlpriv->dm.dm_initialgain_enable = true;
        rtlpriv->dm.dm_flag = 0;
@@ -181,10 +182,10 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
 
        rtlpriv->max_fw_size = 0x8000;
        pr_info("Driver for Realtek RTL8192DE WLAN interface\n");
-       pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
+       pr_info("Loading firmware file %s\n", fw_name);
 
        /* request fw */
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_fw_cb);
        if (err) {
@@ -266,7 +267,6 @@ static const struct rtl_hal_cfg rtl92de_hal_cfg = {
        .bar_id = 2,
        .write_readback = true,
        .name = "rtl8192de",
-       .fw_name = "rtlwifi/rtl8192defw.bin",
        .ops = &rtl8192de_hal_ops,
        .mod_params = &rtl92de_mod_params,
 
index ac299cbe59b0daa7a44cfebc6b2c57bc3a616ad1..46b605de36e722301bf1decb7602ec11c3314739 100644 (file)
@@ -91,6 +91,7 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        int err = 0;
+       char *fw_name;
 
        rtl92ee_bt_reg_init(hw);
        rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
@@ -170,11 +171,11 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw)
        }
 
        /* request fw */
-       rtlpriv->cfg->fw_name = "rtlwifi/rtl8192eefw.bin";
+       fw_name = "rtlwifi/rtl8192eefw.bin";
 
        rtlpriv->max_fw_size = 0x8000;
-       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       pr_info("Using firmware %s\n", fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_fw_cb);
        if (err) {
@@ -266,7 +267,6 @@ static const struct rtl_hal_cfg rtl92ee_hal_cfg = {
        .bar_id = 2,
        .write_readback = true,
        .name = "rtl92ee_pci",
-       .fw_name = "rtlwifi/rtl8192eefw.bin",
        .ops = &rtl8192ee_hal_ops,
        .mod_params = &rtl92ee_mod_params,
 
index 5e8e02d5de8aaf50e140f170acc0597042dfa8bb..3e1eaeac4fdce859cb853b5d820ae5075aa83b8a 100644 (file)
@@ -89,12 +89,13 @@ static void rtl92se_fw_cb(const struct firmware *firmware, void *context)
        struct ieee80211_hw *hw = context;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rt_firmware *pfirmware = NULL;
+       char *fw_name = "rtlwifi/rtl8192sefw.bin";
 
        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
                         "Firmware callback routine entered!\n");
        complete(&rtlpriv->firmware_loading_complete);
        if (!firmware) {
-               pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
+               pr_err("Firmware %s not available\n", fw_name);
                rtlpriv->max_fw_size = 0;
                return;
        }
@@ -117,6 +118,7 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        int err = 0;
        u16 earlyrxthreshold = 7;
+       char *fw_name = "rtlwifi/rtl8192sefw.bin";
 
        rtlpriv->dm.dm_initialgain_enable = true;
        rtlpriv->dm.dm_flag = 0;
@@ -214,9 +216,9 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
        rtlpriv->max_fw_size = RTL8190_MAX_FIRMWARE_CODE_SIZE*2 +
                               sizeof(struct fw_hdr);
        pr_info("Driver for Realtek RTL8192SE/RTL8191SE\n"
-               "Loading firmware %s\n", rtlpriv->cfg->fw_name);
+               "Loading firmware %s\n", fw_name);
        /* request fw */
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl92se_fw_cb);
        if (err) {
@@ -310,7 +312,6 @@ static const struct rtl_hal_cfg rtl92se_hal_cfg = {
        .bar_id = 1,
        .write_readback = false,
        .name = "rtl92s_pci",
-       .fw_name = "rtlwifi/rtl8192sefw.bin",
        .ops = &rtl8192se_hal_ops,
        .mod_params = &rtl92se_mod_params,
 
index 89c828ad89f4230186be72e1cc640b4cf2b3309a..c51a9e8234e92417877537e3ce5d566a120e2bd1 100644 (file)
@@ -94,6 +94,7 @@ int rtl8723e_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        int err = 0;
+       char *fw_name = "rtlwifi/rtl8723fw.bin";
 
        rtl8723e_bt_reg_init(hw);
 
@@ -176,14 +177,12 @@ int rtl8723e_init_sw_vars(struct ieee80211_hw *hw)
                return 1;
        }
 
-       if (IS_VENDOR_8723_A_CUT(rtlhal->version))
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw.bin";
-       else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw_B.bin";
+       if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+               fw_name = "rtlwifi/rtl8723fw_B.bin";
 
        rtlpriv->max_fw_size = 0x6000;
-       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       pr_info("Using firmware %s\n", fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_fw_cb);
        if (err) {
@@ -280,7 +279,6 @@ static const struct rtl_hal_cfg rtl8723e_hal_cfg = {
        .bar_id = 2,
        .write_readback = true,
        .name = "rtl8723e_pci",
-       .fw_name = "rtlwifi/rtl8723efw.bin",
        .ops = &rtl8723e_hal_ops,
        .mod_params = &rtl8723e_mod_params,
        .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
index 20b53f035483a0f2dfc63b2e3d65c60d0e669317..847644d1f5f539ff984efb77131b57575df45b7d 100644 (file)
@@ -91,6 +91,7 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       char *fw_name = "rtlwifi/rtl8723befw.bin";
 
        rtl8723be_bt_reg_init(hw);
        rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
@@ -184,8 +185,8 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw)
        }
 
        rtlpriv->max_fw_size = 0x8000;
-       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       pr_info("Using firmware %s\n", fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_fw_cb);
        if (err) {
@@ -280,7 +281,6 @@ static const struct rtl_hal_cfg rtl8723be_hal_cfg = {
        .bar_id = 2,
        .write_readback = true,
        .name = "rtl8723be_pci",
-       .fw_name = "rtlwifi/rtl8723befw.bin",
        .ops = &rtl8723be_hal_ops,
        .mod_params = &rtl8723be_mod_params,
        .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
index 22f687b1f1334cfb7732add791861bc465d1465d..297938e0effd54c47bcc0ff27ea5c5c1552ceb52 100644 (file)
@@ -93,6 +93,7 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw)
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       char *fw_name, *wowlan_fw_name;
 
        rtl8821ae_bt_reg_init(hw);
        rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
@@ -203,17 +204,17 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw)
        }
 
        if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8812aefw.bin";
-               rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8812aefw_wowlan.bin";
+               fw_name = "rtlwifi/rtl8812aefw.bin";
+               wowlan_fw_name = "rtlwifi/rtl8812aefw_wowlan.bin";
        } else {
-               rtlpriv->cfg->fw_name = "rtlwifi/rtl8821aefw.bin";
-               rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8821aefw_wowlan.bin";
+               fw_name = "rtlwifi/rtl8821aefw.bin";
+               wowlan_fw_name = "rtlwifi/rtl8821aefw_wowlan.bin";
        }
 
        rtlpriv->max_fw_size = 0x8000;
        /*load normal firmware*/
-       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
-       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+       pr_info("Using firmware %s\n", fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_fw_cb);
        if (err) {
@@ -222,9 +223,9 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw)
                return 1;
        }
        /*load wowlan firmware*/
-       pr_info("Using firmware %s\n", rtlpriv->cfg->wowlan_fw_name);
+       pr_info("Using firmware %s\n", wowlan_fw_name);
        err = request_firmware_nowait(THIS_MODULE, 1,
-                                     rtlpriv->cfg->wowlan_fw_name,
+                                     wowlan_fw_name,
                                      rtlpriv->io.dev, GFP_KERNEL, hw,
                                      rtl_wowlan_fw_cb);
        if (err) {
@@ -320,7 +321,6 @@ static const struct rtl_hal_cfg rtl8821ae_hal_cfg = {
        .bar_id = 2,
        .write_readback = true,
        .name = "rtl8821ae_pci",
-       .fw_name = "rtlwifi/rtl8821aefw.bin",
        .ops = &rtl8821ae_hal_ops,
        .mod_params = &rtl8821ae_mod_params,
        .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
index 595f7d5d091afcfa1a092b4662d9d56731291cbb..dafe486f844867a1f96637af5fff774bf3ee3afd 100644 (file)
@@ -2278,9 +2278,7 @@ struct rtl_hal_cfg {
        u8 bar_id;
        bool write_readback;
        char *name;
-       char *fw_name;
        char *alt_fw_name;
-       char *wowlan_fw_name;
        struct rtl_hal_ops *ops;
        struct rtl_mod_params *mod_params;
        struct rtl_hal_usbint_cfg *usb_interface_cfg;
index a6e94b1a12cb3f8e8cbac3c9b3074d18cfe82ee3..47fe7f96a242794caf0150f367ae8300bd1d2c48 100644 (file)
@@ -391,7 +391,6 @@ static void wl1271_remove(struct sdio_func *func)
        pm_runtime_get_noresume(&func->dev);
 
        platform_device_unregister(glue->core);
-       kfree(glue);
 }
 
 #ifdef CONFIG_PM
index e17879dd5d5a18e3efcfe0d64a4fb992d2967b96..bf2744e1e3db9436cdf9c5f115a175afcb1ed6b5 100644 (file)
@@ -304,7 +304,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue)
                queue->rx_skbs[id] = skb;
 
                ref = gnttab_claim_grant_reference(&queue->gref_rx_head);
-               BUG_ON((signed short)ref < 0);
+               WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref));
                queue->grant_rx_ref[id] = ref;
 
                page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
@@ -428,7 +428,7 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset,
        id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs);
        tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++);
        ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
-       BUG_ON((signed short)ref < 0);
+       WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref));
 
        gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id,
                                        gfn, GNTMAP_readonly);
index 83deda4bb4d6d52d4b529b71712f71114aac1445..6f9563a9648852e48929a39b29982a7bbef52c0e 100644 (file)
@@ -133,7 +133,7 @@ static int mei_nfc_if_version(struct nfc_mei_phy *phy)
                return -ENOMEM;
 
        bytes_recv = mei_cldev_recv(phy->cldev, (u8 *)reply, if_version_length);
-       if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+       if (bytes_recv < 0 || bytes_recv < if_version_length) {
                pr_err("Could not read IF version\n");
                r = -EIO;
                goto err;
index 0d5c29ae51def6735e21aafb6579cda7c56ebd6f..7310a261c858bab090bab14ecf3646626aac7651 100644 (file)
@@ -112,17 +112,17 @@ MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64,
 
 module_param_named(xeon_b2b_usd_bar4_addr64,
                   xeon_b2b_usd_addr.bar4_addr64, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64,
+MODULE_PARM_DESC(xeon_b2b_usd_bar4_addr64,
                 "XEON B2B USD BAR 4 64-bit address");
 
 module_param_named(xeon_b2b_usd_bar4_addr32,
                   xeon_b2b_usd_addr.bar4_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64,
+MODULE_PARM_DESC(xeon_b2b_usd_bar4_addr32,
                 "XEON B2B USD split-BAR 4 32-bit address");
 
 module_param_named(xeon_b2b_usd_bar5_addr32,
                   xeon_b2b_usd_addr.bar5_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64,
+MODULE_PARM_DESC(xeon_b2b_usd_bar5_addr32,
                 "XEON B2B USD split-BAR 5 32-bit address");
 
 module_param_named(xeon_b2b_dsd_bar2_addr64,
@@ -132,17 +132,17 @@ MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64,
 
 module_param_named(xeon_b2b_dsd_bar4_addr64,
                   xeon_b2b_dsd_addr.bar4_addr64, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64,
+MODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr64,
                 "XEON B2B DSD BAR 4 64-bit address");
 
 module_param_named(xeon_b2b_dsd_bar4_addr32,
                   xeon_b2b_dsd_addr.bar4_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64,
+MODULE_PARM_DESC(xeon_b2b_dsd_bar4_addr32,
                 "XEON B2B DSD split-BAR 4 32-bit address");
 
 module_param_named(xeon_b2b_dsd_bar5_addr32,
                   xeon_b2b_dsd_addr.bar5_addr32, ullong, 0644);
-MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64,
+MODULE_PARM_DESC(xeon_b2b_dsd_bar5_addr32,
                 "XEON B2B DSD split-BAR 5 32-bit address");
 
 #ifndef ioread64
@@ -1755,6 +1755,8 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev,
                                            XEON_B2B_MIN_SIZE);
                if (!ndev->peer_mmio)
                        return -EIO;
+
+               ndev->peer_addr = pci_resource_start(pdev, b2b_bar);
        }
 
        return 0;
@@ -2019,6 +2021,7 @@ static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev)
                goto err_mmio;
        }
        ndev->peer_mmio = ndev->self_mmio;
+       ndev->peer_addr = pci_resource_start(pdev, 0);
 
        return 0;
 
index 8601c10acf74e3267d1d5501e20149ce74cdb38b..4eb8adb345084430947ccabdf6962c1099fbb703 100644 (file)
@@ -257,7 +257,7 @@ enum {
 #define NTB_QP_DEF_NUM_ENTRIES 100
 #define NTB_LINK_DOWN_TIMEOUT  10
 #define DMA_RETRIES            20
-#define DMA_OUT_RESOURCE_TO    50
+#define DMA_OUT_RESOURCE_TO    msecs_to_jiffies(50)
 
 static void ntb_transport_rxc_db(unsigned long data);
 static const struct ntb_ctx_ops ntb_transport_ops;
index 6a50f20bf1cde0e080f766ede5df147a9ea11a7b..e75d4fdc08663905eace859cff6cdebdb97e92b5 100644 (file)
@@ -72,7 +72,7 @@
 #define MAX_THREADS            32
 #define MAX_TEST_SIZE          SZ_1M
 #define MAX_SRCS               32
-#define DMA_OUT_RESOURCE_TO    50
+#define DMA_OUT_RESOURCE_TO    msecs_to_jiffies(50)
 #define DMA_RETRIES            20
 #define SZ_4G                  (1ULL << 32)
 #define MAX_SEG_ORDER          20 /* no larger than 1M for kmalloc buffer */
@@ -589,7 +589,7 @@ static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf,
                return -ENOMEM;
 
        if (mutex_is_locked(&perf->run_mutex)) {
-               out_off = snprintf(buf, 64, "running\n");
+               out_off = scnprintf(buf, 64, "running\n");
                goto read_from_buf;
        }
 
@@ -600,14 +600,14 @@ static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf,
                        break;
 
                if (pctx->status) {
-                       out_off += snprintf(buf + out_off, 1024 - out_off,
+                       out_off += scnprintf(buf + out_off, 1024 - out_off,
                                            "%d: error %d\n", i,
                                            pctx->status);
                        continue;
                }
 
                rate = div64_u64(pctx->copied, pctx->diff_us);
-               out_off += snprintf(buf + out_off, 1024 - out_off,
+               out_off += scnprintf(buf + out_off, 1024 - out_off,
                        "%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n",
                        i, pctx->copied, pctx->diff_us, rate);
        }
index 7d311799fca1696ee7c5884fa2d58af2f2061816..435861189d97f87fc07397e6a174571d524bdb6f 100644 (file)
@@ -88,7 +88,7 @@ MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer");
 
 static unsigned long db_init = 0x7;
 module_param(db_init, ulong, 0644);
-MODULE_PARM_DESC(delay_ms, "Initial doorbell bits to ring on the peer");
+MODULE_PARM_DESC(db_init, "Initial doorbell bits to ring on the peer");
 
 struct pp_ctx {
        struct ntb_dev                  *ntb;
index 8b2b740d6679e61f544a990164eb9e8f2e614f42..124c2432ac9cb3d6e0a696023507f5131774c282 100644 (file)
@@ -89,7 +89,7 @@ config NVDIMM_PFN
          Select Y if unsure
 
 config NVDIMM_DAX
-       tristate "NVDIMM DAX: Raw access to persistent memory"
+       bool "NVDIMM DAX: Raw access to persistent memory"
        default LIBNVDIMM
        depends on NVDIMM_PFN
        help
index a8b6949a8778835a89cef3469f031b77956d0c45..23d4a1728cdfa4993903b6b4504c6a70f5a7fff4 100644 (file)
@@ -715,7 +715,7 @@ EXPORT_SYMBOL_GPL(nd_cmd_in_size);
 
 u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
                const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
-               const u32 *out_field)
+               const u32 *out_field, unsigned long remainder)
 {
        if (idx >= desc->out_num)
                return UINT_MAX;
@@ -727,9 +727,24 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
                return in_field[1];
        else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
                return out_field[1];
-       else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2)
-               return out_field[1] - 8;
-       else if (cmd == ND_CMD_CALL) {
+       else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2) {
+               /*
+                * Per table 9-276 ARS Data in ACPI 6.1, out_field[1] is
+                * "Size of Output Buffer in bytes, including this
+                * field."
+                */
+               if (out_field[1] < 4)
+                       return 0;
+               /*
+                * ACPI 6.1 is ambiguous if 'status' is included in the
+                * output size. If we encounter an output size that
+                * overshoots the remainder by 4 bytes, assume it was
+                * including 'status'.
+                */
+               if (out_field[1] - 8 == remainder)
+                       return remainder;
+               return out_field[1] - 4;
+       } else if (cmd == ND_CMD_CALL) {
                struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field;
 
                return pkg->nd_size_out;
@@ -876,7 +891,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
        /* process an output envelope */
        for (i = 0; i < desc->out_num; i++) {
                u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
-                               (u32 *) in_env, (u32 *) out_env);
+                               (u32 *) in_env, (u32 *) out_env, 0);
                u32 copy;
 
                if (out_size == UINT_MAX) {
index 3509cff68ef9c73e1c5bfe79829acfc4b4467cdf..abe5c6bc756c255193d803039973971368b9471d 100644 (file)
@@ -2176,12 +2176,14 @@ static struct device **scan_labels(struct nd_region *nd_region)
        return devs;
 
  err:
-       for (i = 0; devs[i]; i++)
-               if (is_nd_blk(&nd_region->dev))
-                       namespace_blk_release(devs[i]);
-               else
-                       namespace_pmem_release(devs[i]);
-       kfree(devs);
+       if (devs) {
+               for (i = 0; devs[i]; i++)
+                       if (is_nd_blk(&nd_region->dev))
+                               namespace_blk_release(devs[i]);
+                       else
+                               namespace_pmem_release(devs[i]);
+               kfree(devs);
+       }
        return NULL;
 }
 
index 42b3a82170733971a3b1d000b8de4979f0ad311b..24618431a14bae7e891438b3601d017d1d34db4d 100644 (file)
@@ -47,7 +47,7 @@ static struct nd_region *to_region(struct pmem_device *pmem)
        return to_nd_region(to_dev(pmem)->parent);
 }
 
-static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
+static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
                unsigned int len)
 {
        struct device *dev = to_dev(pmem);
@@ -62,8 +62,12 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
                                __func__, (unsigned long long) sector,
                                cleared / 512, cleared / 512 > 1 ? "s" : "");
                badblocks_clear(&pmem->bb, sector, cleared / 512);
+       } else {
+               return -EIO;
        }
+
        invalidate_pmem(pmem->virt_addr + offset, len);
+       return 0;
 }
 
 static void write_pmem(void *pmem_addr, struct page *page,
@@ -123,7 +127,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
                flush_dcache_page(page);
                write_pmem(pmem_addr, page, off, len);
                if (unlikely(bad_pmem)) {
-                       pmem_clear_poison(pmem, pmem_off, len);
+                       rc = pmem_clear_poison(pmem, pmem_off, len);
                        write_pmem(pmem_addr, page, off, len);
                }
        }
index 329381a28edf8a7e4b3bb4c6ca2da669ee9caa4a..79e679d12f3b3667ad815e0bd39ab428da6651ac 100644 (file)
@@ -554,7 +554,7 @@ int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
 
        /* gcc-4.4.4 (at least) has issues with initializers and anon unions */
        c.identify.opcode = nvme_admin_identify;
-       c.identify.cns = cpu_to_le32(1);
+       c.identify.cns = cpu_to_le32(NVME_ID_CNS_CTRL);
 
        *id = kmalloc(sizeof(struct nvme_id_ctrl), GFP_KERNEL);
        if (!*id)
@@ -572,7 +572,7 @@ static int nvme_identify_ns_list(struct nvme_ctrl *dev, unsigned nsid, __le32 *n
        struct nvme_command c = { };
 
        c.identify.opcode = nvme_admin_identify;
-       c.identify.cns = cpu_to_le32(2);
+       c.identify.cns = cpu_to_le32(NVME_ID_CNS_NS_ACTIVE_LIST);
        c.identify.nsid = cpu_to_le32(nsid);
        return nvme_submit_sync_cmd(dev->admin_q, &c, ns_list, 0x1000);
 }
@@ -900,9 +900,9 @@ static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id)
                return -ENODEV;
        }
 
-       if (ns->ctrl->vs >= NVME_VS(1, 1))
+       if (ns->ctrl->vs >= NVME_VS(1, 1, 0))
                memcpy(ns->eui, (*id)->eui64, sizeof(ns->eui));
-       if (ns->ctrl->vs >= NVME_VS(1, 2))
+       if (ns->ctrl->vs >= NVME_VS(1, 2, 0))
                memcpy(ns->uuid, (*id)->nguid, sizeof(ns->uuid));
 
        return 0;
@@ -1086,6 +1086,8 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled)
        int ret;
 
        while ((ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &csts)) == 0) {
+               if (csts == ~0)
+                       return -ENODEV;
                if ((csts & NVME_CSTS_RDY) == bit)
                        break;
 
@@ -1240,7 +1242,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
        }
        page_shift = NVME_CAP_MPSMIN(cap) + 12;
 
-       if (ctrl->vs >= NVME_VS(1, 1))
+       if (ctrl->vs >= NVME_VS(1, 1, 0))
                ctrl->subsystem = NVME_CAP_NSSRC(cap);
 
        ret = nvme_identify_ctrl(ctrl, &id);
@@ -1840,7 +1842,7 @@ static void nvme_scan_work(struct work_struct *work)
                return;
 
        nn = le32_to_cpu(id->nn);
-       if (ctrl->vs >= NVME_VS(1, 1) &&
+       if (ctrl->vs >= NVME_VS(1, 1, 0) &&
            !(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
                if (!nvme_scan_ns_list(ctrl, nn))
                        goto done;
index f5e3011e31fcdfea4c4e067ca8b808bc66a2fffd..5daf2f4be0cd74d5cc1360ed95ceb7c9a10385ea 100644 (file)
@@ -612,7 +612,7 @@ int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node,
 
        ret = nvm_register(dev);
 
-       ns->lba_shift = ilog2(dev->sec_size) - 9;
+       ns->lba_shift = ilog2(dev->sec_size);
 
        if (sysfs_create_group(&dev->dev.kobj, attrs))
                pr_warn("%s: failed to create sysfs group for identification\n",
index 0fc99f0f257110a063f3e58722b2f0ec08da655e..5e52034ab01049e3f9935e44bee4a8b125769582 100644 (file)
@@ -99,6 +99,7 @@ struct nvme_dev {
        dma_addr_t cmb_dma_addr;
        u64 cmb_size;
        u32 cmbsz;
+       u32 cmbloc;
        struct nvme_ctrl ctrl;
        struct completion ioq_wait;
 };
@@ -893,7 +894,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
                         "I/O %d QID %d timeout, reset controller\n",
                         req->tag, nvmeq->qid);
                nvme_dev_disable(dev, false);
-               queue_work(nvme_workq, &dev->reset_work);
+               nvme_reset(dev);
 
                /*
                 * Mark the request as handled, since the inline shutdown
@@ -1214,7 +1215,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
        u64 cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
        struct nvme_queue *nvmeq;
 
-       dev->subsystem = readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 1) ?
+       dev->subsystem = readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 1, 0) ?
                                                NVME_CAP_NSSRC(cap) : 0;
 
        if (dev->subsystem &&
@@ -1241,20 +1242,16 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
 
        result = nvme_enable_ctrl(&dev->ctrl, cap);
        if (result)
-               goto free_nvmeq;
+               return result;
 
        nvmeq->cq_vector = 0;
        result = queue_request_irq(nvmeq);
        if (result) {
                nvmeq->cq_vector = -1;
-               goto free_nvmeq;
+               return result;
        }
 
        return result;
-
- free_nvmeq:
-       nvme_free_queues(dev, 0);
-       return result;
 }
 
 static bool nvme_should_reset(struct nvme_dev *dev, u32 csts)
@@ -1291,7 +1288,7 @@ static void nvme_watchdog_timer(unsigned long data)
 
        /* Skip controllers under certain specific conditions. */
        if (nvme_should_reset(dev, csts)) {
-               if (queue_work(nvme_workq, &dev->reset_work))
+               if (!nvme_reset(dev))
                        dev_warn(dev->dev,
                                "Failed status: 0x%x, reset controller.\n",
                                csts);
@@ -1316,10 +1313,8 @@ static int nvme_create_io_queues(struct nvme_dev *dev)
        max = min(dev->max_qid, dev->queue_count - 1);
        for (i = dev->online_queues; i <= max; i++) {
                ret = nvme_create_queue(dev->queues[i], i);
-               if (ret) {
-                       nvme_free_queues(dev, i);
+               if (ret)
                        break;
-               }
        }
 
        /*
@@ -1331,28 +1326,37 @@ static int nvme_create_io_queues(struct nvme_dev *dev)
        return ret >= 0 ? 0 : ret;
 }
 
+static ssize_t nvme_cmb_show(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       struct nvme_dev *ndev = to_nvme_dev(dev_get_drvdata(dev));
+
+       return snprintf(buf, PAGE_SIZE, "cmbloc : x%08x\ncmbsz  : x%08x\n",
+                      ndev->cmbloc, ndev->cmbsz);
+}
+static DEVICE_ATTR(cmb, S_IRUGO, nvme_cmb_show, NULL);
+
 static void __iomem *nvme_map_cmb(struct nvme_dev *dev)
 {
        u64 szu, size, offset;
-       u32 cmbloc;
        resource_size_t bar_size;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
        void __iomem *cmb;
        dma_addr_t dma_addr;
 
-       if (!use_cmb_sqes)
-               return NULL;
-
        dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
        if (!(NVME_CMB_SZ(dev->cmbsz)))
                return NULL;
+       dev->cmbloc = readl(dev->bar + NVME_REG_CMBLOC);
 
-       cmbloc = readl(dev->bar + NVME_REG_CMBLOC);
+       if (!use_cmb_sqes)
+               return NULL;
 
        szu = (u64)1 << (12 + 4 * NVME_CMB_SZU(dev->cmbsz));
        size = szu * NVME_CMB_SZ(dev->cmbsz);
-       offset = szu * NVME_CMB_OFST(cmbloc);
-       bar_size = pci_resource_len(pdev, NVME_CMB_BIR(cmbloc));
+       offset = szu * NVME_CMB_OFST(dev->cmbloc);
+       bar_size = pci_resource_len(pdev, NVME_CMB_BIR(dev->cmbloc));
 
        if (offset > bar_size)
                return NULL;
@@ -1365,7 +1369,7 @@ static void __iomem *nvme_map_cmb(struct nvme_dev *dev)
        if (size > bar_size - offset)
                size = bar_size - offset;
 
-       dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(cmbloc)) + offset;
+       dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(dev->cmbloc)) + offset;
        cmb = ioremap_wc(dma_addr, size);
        if (!cmb)
                return NULL;
@@ -1450,13 +1454,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
        result = queue_request_irq(adminq);
        if (result) {
                adminq->cq_vector = -1;
-               goto free_queues;
+               return result;
        }
        return nvme_create_io_queues(dev);
-
- free_queues:
-       nvme_free_queues(dev, 1);
-       return result;
 }
 
 static void nvme_del_queue_end(struct request *req, int error)
@@ -1511,9 +1511,9 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
        return 0;
 }
 
-static void nvme_disable_io_queues(struct nvme_dev *dev)
+static void nvme_disable_io_queues(struct nvme_dev *dev, int queues)
 {
-       int pass, queues = dev->online_queues - 1;
+       int pass;
        unsigned long timeout;
        u8 opcode = nvme_admin_delete_sq;
 
@@ -1616,9 +1616,25 @@ static int nvme_pci_enable(struct nvme_dev *dev)
                        dev->q_depth);
        }
 
-       if (readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 2))
+       /*
+        * CMBs can currently only exist on >=1.2 PCIe devices. We only
+        * populate sysfs if a CMB is implemented. Note that we add the
+        * CMB attribute to the nvme_ctrl kobj which removes the need to remove
+        * it on exit. Since nvme_dev_attrs_group has no name we can pass
+        * NULL as final argument to sysfs_add_file_to_group.
+        */
+
+       if (readl(dev->bar + NVME_REG_VS) >= NVME_VS(1, 2, 0)) {
                dev->cmb = nvme_map_cmb(dev);
 
+               if (dev->cmbsz) {
+                       if (sysfs_add_file_to_group(&dev->ctrl.device->kobj,
+                                                   &dev_attr_cmb.attr, NULL))
+                               dev_warn(dev->dev,
+                                        "failed to add sysfs attribute for CMB\n");
+               }
+       }
+
        pci_enable_pcie_error_reporting(pdev);
        pci_save_state(pdev);
        return 0;
@@ -1649,7 +1665,7 @@ static void nvme_pci_disable(struct nvme_dev *dev)
 
 static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
 {
-       int i;
+       int i, queues;
        u32 csts = -1;
 
        del_timer_sync(&dev->watchdog_timer);
@@ -1660,6 +1676,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
                csts = readl(dev->bar + NVME_REG_CSTS);
        }
 
+       queues = dev->online_queues - 1;
        for (i = dev->queue_count - 1; i > 0; i--)
                nvme_suspend_queue(dev->queues[i]);
 
@@ -1671,7 +1688,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
                if (dev->queue_count)
                        nvme_suspend_queue(dev->queues[0]);
        } else {
-               nvme_disable_io_queues(dev);
+               nvme_disable_io_queues(dev, queues);
                nvme_disable_admin_queue(dev, shutdown);
        }
        nvme_pci_disable(dev);
@@ -1818,11 +1835,10 @@ static int nvme_reset(struct nvme_dev *dev)
 {
        if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
                return -ENODEV;
-
+       if (work_busy(&dev->reset_work))
+               return -ENODEV;
        if (!queue_work(nvme_workq, &dev->reset_work))
                return -EBUSY;
-
-       flush_work(&dev->reset_work);
        return 0;
 }
 
@@ -1846,7 +1862,12 @@ static int nvme_pci_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val)
 
 static int nvme_pci_reset_ctrl(struct nvme_ctrl *ctrl)
 {
-       return nvme_reset(to_nvme_dev(ctrl));
+       struct nvme_dev *dev = to_nvme_dev(ctrl);
+       int ret = nvme_reset(dev);
+
+       if (!ret)
+               flush_work(&dev->reset_work);
+       return ret;
 }
 
 static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
@@ -1940,7 +1961,7 @@ static void nvme_reset_notify(struct pci_dev *pdev, bool prepare)
        if (prepare)
                nvme_dev_disable(dev, false);
        else
-               queue_work(nvme_workq, &dev->reset_work);
+               nvme_reset(dev);
 }
 
 static void nvme_shutdown(struct pci_dev *pdev)
@@ -2009,7 +2030,7 @@ static int nvme_resume(struct device *dev)
        struct pci_dev *pdev = to_pci_dev(dev);
        struct nvme_dev *ndev = pci_get_drvdata(pdev);
 
-       queue_work(nvme_workq, &ndev->reset_work);
+       nvme_reset(ndev);
        return 0;
 }
 #endif
@@ -2048,7 +2069,7 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev)
 
        dev_info(dev->ctrl.device, "restart after slot reset\n");
        pci_restore_state(pdev);
-       queue_work(nvme_workq, &dev->reset_work);
+       nvme_reset(dev);
        return PCI_ERS_RESULT_RECOVERED;
 }
 
index 5a8388177959916dc4dadbc5e6d8c366b0eb6b81..3d25add36d91993ddbc45572c6bc10213deea9d9 100644 (file)
@@ -83,6 +83,7 @@ enum nvme_rdma_queue_flags {
        NVME_RDMA_Q_CONNECTED = (1 << 0),
        NVME_RDMA_IB_QUEUE_ALLOCATED = (1 << 1),
        NVME_RDMA_Q_DELETING = (1 << 2),
+       NVME_RDMA_Q_LIVE = (1 << 3),
 };
 
 struct nvme_rdma_queue {
@@ -624,10 +625,18 @@ static int nvme_rdma_connect_io_queues(struct nvme_rdma_ctrl *ctrl)
 
        for (i = 1; i < ctrl->queue_count; i++) {
                ret = nvmf_connect_io_queue(&ctrl->ctrl, i);
-               if (ret)
-                       break;
+               if (ret) {
+                       dev_info(ctrl->ctrl.device,
+                               "failed to connect i/o queue: %d\n", ret);
+                       goto out_free_queues;
+               }
+               set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[i].flags);
        }
 
+       return 0;
+
+out_free_queues:
+       nvme_rdma_free_io_queues(ctrl);
        return ret;
 }
 
@@ -712,6 +721,8 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work)
        if (ret)
                goto stop_admin_q;
 
+       set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[0].flags);
+
        ret = nvme_enable_ctrl(&ctrl->ctrl, ctrl->cap);
        if (ret)
                goto stop_admin_q;
@@ -761,8 +772,10 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
 
        nvme_stop_keep_alive(&ctrl->ctrl);
 
-       for (i = 0; i < ctrl->queue_count; i++)
+       for (i = 0; i < ctrl->queue_count; i++) {
                clear_bit(NVME_RDMA_Q_CONNECTED, &ctrl->queues[i].flags);
+               clear_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[i].flags);
+       }
 
        if (ctrl->queue_count > 1)
                nvme_stop_queues(&ctrl->ctrl);
@@ -1378,6 +1391,24 @@ nvme_rdma_timeout(struct request *rq, bool reserved)
        return BLK_EH_HANDLED;
 }
 
+/*
+ * We cannot accept any other command until the Connect command has completed.
+ */
+static inline bool nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue,
+               struct request *rq)
+{
+       if (unlikely(!test_bit(NVME_RDMA_Q_LIVE, &queue->flags))) {
+               struct nvme_command *cmd = (struct nvme_command *)rq->cmd;
+
+               if (rq->cmd_type != REQ_TYPE_DRV_PRIV ||
+                   cmd->common.opcode != nvme_fabrics_command ||
+                   cmd->fabrics.fctype != nvme_fabrics_type_connect)
+                       return false;
+       }
+
+       return true;
+}
+
 static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
                const struct blk_mq_queue_data *bd)
 {
@@ -1394,6 +1425,9 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 
        WARN_ON_ONCE(rq->tag < 0);
 
+       if (!nvme_rdma_queue_is_ready(queue, rq))
+               return BLK_MQ_RQ_QUEUE_BUSY;
+
        dev = queue->device->dev;
        ib_dma_sync_single_for_cpu(dev, sqe->dma,
                        sizeof(struct nvme_command), DMA_TO_DEVICE);
@@ -1544,6 +1578,8 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl)
        if (error)
                goto out_cleanup_queue;
 
+       set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[0].flags);
+
        error = nvmf_reg_read64(&ctrl->ctrl, NVME_REG_CAP, &ctrl->cap);
        if (error) {
                dev_err(ctrl->ctrl.device,
index c2a0a1c7d05d1571c939f531d3619b5800cadbd6..3eaa4d27801ee17c7e1ccaa1b8a489844cb6f5bc 100644 (file)
@@ -606,7 +606,7 @@ static int nvme_fill_device_id_eui64(struct nvme_ns *ns, struct sg_io_hdr *hdr,
        eui = id_ns->eui64;
        len = sizeof(id_ns->eui64);
 
-       if (ns->ctrl->vs >= NVME_VS(1, 2)) {
+       if (ns->ctrl->vs >= NVME_VS(1, 2, 0)) {
                if (bitmap_empty(eui, len * 8)) {
                        eui = id_ns->nguid;
                        len = sizeof(id_ns->nguid);
@@ -679,7 +679,7 @@ static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
 {
        int res;
 
-       if (ns->ctrl->vs >= NVME_VS(1, 1)) {
+       if (ns->ctrl->vs >= NVME_VS(1, 1, 0)) {
                res = nvme_fill_device_id_eui64(ns, hdr, resp, alloc_len);
                if (res != -EOPNOTSUPP)
                        return res;
index 7ab9c9381b989578cb5faaf6054721ace331c631..6fe4c48a21e46520ad1e0e569a9773813ed7e233 100644 (file)
@@ -199,7 +199,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
         */
 
        /* we support multiple ports and multiples hosts: */
-       id->mic = (1 << 0) | (1 << 1);
+       id->cmic = (1 << 0) | (1 << 1);
 
        /* no limit on data transfer sizes for now */
        id->mdts = 0;
@@ -511,13 +511,13 @@ int nvmet_parse_admin_cmd(struct nvmet_req *req)
        case nvme_admin_identify:
                req->data_len = 4096;
                switch (le32_to_cpu(cmd->identify.cns)) {
-               case 0x00:
+               case NVME_ID_CNS_NS:
                        req->execute = nvmet_execute_identify_ns;
                        return 0;
-               case 0x01:
+               case NVME_ID_CNS_CTRL:
                        req->execute = nvmet_execute_identify_ctrl;
                        return 0;
-               case 0x02:
+               case NVME_ID_CNS_NS_ACTIVE_LIST:
                        req->execute = nvmet_execute_identify_nslist;
                        return 0;
                }
index 6559d5afa7bfd9f808281658f686429c53fc7903..a21437a33adbef0c51395c0b88f2e8a10995ea86 100644 (file)
@@ -838,9 +838,13 @@ static void nvmet_fatal_error_handler(struct work_struct *work)
 
 void nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl)
 {
-       ctrl->csts |= NVME_CSTS_CFS;
-       INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler);
-       schedule_work(&ctrl->fatal_err_work);
+       mutex_lock(&ctrl->lock);
+       if (!(ctrl->csts & NVME_CSTS_CFS)) {
+               ctrl->csts |= NVME_CSTS_CFS;
+               INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler);
+               schedule_work(&ctrl->fatal_err_work);
+       }
+       mutex_unlock(&ctrl->lock);
 }
 EXPORT_SYMBOL_GPL(nvmet_ctrl_fatal_error);
 
@@ -882,7 +886,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
        if (!subsys)
                return NULL;
 
-       subsys->ver = (1 << 16) | (2 << 8) | 1; /* NVMe 1.2.1 */
+       subsys->ver = NVME_VS(1, 2, 1); /* NVMe 1.2.1 */
 
        switch (type) {
        case NVME_NQN_NVME:
index 6f65646e89cfd9bc21a95946bfa4fbbe26eb835d..12f39eea569f2fb33cec45884c188d0ad8ae2493 100644 (file)
@@ -54,7 +54,7 @@ static void nvmet_format_discovery_entry(struct nvmf_disc_rsp_page_hdr *hdr,
        /* we support only dynamic controllers */
        e->cntlid = cpu_to_le16(NVME_CNTLID_DYNAMIC);
        e->asqsz = cpu_to_le16(NVMF_AQ_DEPTH);
-       e->nqntype = type;
+       e->subtype = type;
        memcpy(e->trsvcid, port->disc_addr.trsvcid, NVMF_TRSVCID_SIZE);
        memcpy(e->traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE);
        memcpy(e->tsas.common, port->disc_addr.tsas.common, NVMF_TSAS_SIZE);
@@ -187,7 +187,7 @@ int nvmet_parse_discovery_cmd(struct nvmet_req *req)
        case nvme_admin_identify:
                req->data_len = 4096;
                switch (le32_to_cpu(cmd->identify.cns)) {
-               case 0x01:
+               case NVME_ID_CNS_CTRL:
                        req->execute =
                                nvmet_execute_identify_disc_ctrl;
                        return 0;
index f8d23999e0f2c28b98934c6a790b3a6c2bde26d1..005ef5d17a191101b3b2da09a0a1c702f5a6c400 100644 (file)
@@ -951,6 +951,7 @@ err_destroy_cq:
 
 static void nvmet_rdma_destroy_queue_ib(struct nvmet_rdma_queue *queue)
 {
+       ib_drain_qp(queue->cm_id->qp);
        rdma_destroy_qp(queue->cm_id);
        ib_free_cq(queue->cq);
 }
@@ -1066,6 +1067,7 @@ nvmet_rdma_alloc_queue(struct nvmet_rdma_device *ndev,
        spin_lock_init(&queue->rsp_wr_wait_lock);
        INIT_LIST_HEAD(&queue->free_rsps);
        spin_lock_init(&queue->rsps_lock);
+       INIT_LIST_HEAD(&queue->queue_list);
 
        queue->idx = ida_simple_get(&nvmet_rdma_queue_ida, 0, 0, GFP_KERNEL);
        if (queue->idx < 0) {
@@ -1244,7 +1246,6 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue)
 
        if (disconnect) {
                rdma_disconnect(queue->cm_id);
-               ib_drain_qp(queue->cm_id->qp);
                schedule_work(&queue->release_work);
        }
 }
@@ -1269,7 +1270,12 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id,
 {
        WARN_ON_ONCE(queue->state != NVMET_RDMA_Q_CONNECTING);
 
-       pr_err("failed to connect queue\n");
+       mutex_lock(&nvmet_rdma_queue_mutex);
+       if (!list_empty(&queue->queue_list))
+               list_del_init(&queue->queue_list);
+       mutex_unlock(&nvmet_rdma_queue_mutex);
+
+       pr_err("failed to connect queue %d\n", queue->idx);
        schedule_work(&queue->release_work);
 }
 
@@ -1352,7 +1358,13 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id,
        case RDMA_CM_EVENT_ADDR_CHANGE:
        case RDMA_CM_EVENT_DISCONNECTED:
        case RDMA_CM_EVENT_TIMEWAIT_EXIT:
-               nvmet_rdma_queue_disconnect(queue);
+               /*
+                * We might end up here when we already freed the qp
+                * which means queue release sequence is in progress,
+                * so don't get in the way...
+                */
+               if (queue)
+                       nvmet_rdma_queue_disconnect(queue);
                break;
        case RDMA_CM_EVENT_DEVICE_REMOVAL:
                ret = nvmet_rdma_device_removal(cm_id, queue);
index d687e6de24a07e11a2c2cecd94e7711610d52005..a0bccb54a9bd1d762d42967e6722b43d1b4a93ec 100644 (file)
@@ -2077,8 +2077,6 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
                        name = of_get_property(of_aliases, "stdout", NULL);
                if (name)
                        of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
-               if (of_stdout)
-                       console_set_by_of();
        }
 
        if (!of_aliases)
index b470f7e3521d49c73877b6156bc9db7b926fdc51..262281bd68fa3c4d39e13f52eeafea1948d1bd22 100644 (file)
@@ -292,6 +292,7 @@ struct phy_device *of_phy_find_device(struct device_node *phy_np)
                mdiodev = to_mdio_device(d);
                if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY)
                        return to_phy_device(d);
+               put_device(d);
        }
 
        return NULL;
@@ -456,8 +457,11 @@ int of_phy_register_fixed_link(struct device_node *np)
                status.link = 1;
                status.duplex = of_property_read_bool(fixed_link_node,
                                                      "full-duplex");
-               if (of_property_read_u32(fixed_link_node, "speed", &status.speed))
+               if (of_property_read_u32(fixed_link_node, "speed",
+                                        &status.speed)) {
+                       of_node_put(fixed_link_node);
                        return -EINVAL;
+               }
                status.pause = of_property_read_bool(fixed_link_node, "pause");
                status.asym_pause = of_property_read_bool(fixed_link_node,
                                                          "asym-pause");
@@ -486,3 +490,18 @@ int of_phy_register_fixed_link(struct device_node *np)
        return -ENODEV;
 }
 EXPORT_SYMBOL(of_phy_register_fixed_link);
+
+void of_phy_deregister_fixed_link(struct device_node *np)
+{
+       struct phy_device *phydev;
+
+       phydev = of_phy_find_device(np);
+       if (!phydev)
+               return;
+
+       fixed_phy_unregister(phydev);
+
+       put_device(&phydev->mdio.dev);  /* of_phy_find_device() */
+       phy_device_free(phydev);        /* fixed_phy_register() */
+}
+EXPORT_SYMBOL(of_phy_deregister_fixed_link);
index 2cb7315e26d089701679e23a7fc3f8a9ce74e4cf..6537079963424b09bba4df9f0de93bd2a1e5820e 100644 (file)
@@ -247,6 +247,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
 
        pp = &pcie->pp;
        pp->dev = dev;
+       pcie->drvdata = match->data;
        pp->ops = pcie->drvdata->ops;
 
        dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
@@ -256,7 +257,6 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
                return PTR_ERR(pcie->pp.dbi_base);
        }
 
-       pcie->drvdata = match->data;
        pcie->lut = pcie->pp.dbi_base + pcie->drvdata->lut_offset;
 
        if (!ls_pcie_is_bridge(pcie))
index 537f58a664fa230d3f6496ff68f4e7495d0f5952..1a02038c464021b9580a37e2ee70b71a365ecc28 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
  *
- * Authors: Joao Pinto <jpinto@synopsys.com>
+ * Authors: Joao Pinto <Joao.Pinto@synopsys.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index 035f50c03281c803f82d721c0a3c3a2c10a4a348..bed19994c1e94d4e32c134e58133c4acd8b8bd88 100644 (file)
@@ -637,8 +637,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
-       pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp);
-
        if (pp->ops->host_init)
                pp->ops->host_init(pp);
 
@@ -809,6 +807,11 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 {
        u32 val;
 
+       /* get iATU unroll support */
+       pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp);
+       dev_dbg(pp->dev, "iATU unroll: %s\n",
+               pp->iatu_unroll_enabled ? "enabled" : "disabled");
+
        /* set the number of lanes */
        val = dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL);
        val &= ~PORT_LINK_MODE_MASK;
index ef0a84c7a5885e1d62df499353f1384d86a5fceb..35936409b2d45921a049db1d4ddcbc64c4bb8f04 100644 (file)
@@ -533,11 +533,11 @@ static int qcom_pcie_probe(struct platform_device *pdev)
        if (IS_ERR(pcie->phy))
                return PTR_ERR(pcie->phy);
 
+       pp->dev = dev;
        ret = pcie->ops->get_resources(pcie);
        if (ret)
                return ret;
 
-       pp->dev = dev;
        pp->root_bus_nr = -1;
        pp->ops = &qcom_pcie_dw_ops;
 
index e0b22dab9b7ac37c81d380bfe00751f4496f4516..e04f69beb42d0f8ef04de5da85702f238ff2a8a5 100644 (file)
@@ -190,6 +190,9 @@ struct rockchip_pcie {
        struct  reset_control *mgmt_rst;
        struct  reset_control *mgmt_sticky_rst;
        struct  reset_control *pipe_rst;
+       struct  reset_control *pm_rst;
+       struct  reset_control *aclk_rst;
+       struct  reset_control *pclk_rst;
        struct  clk *aclk_pcie;
        struct  clk *aclk_perf_pcie;
        struct  clk *hclk_pcie;
@@ -408,6 +411,44 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
 
        gpiod_set_value(rockchip->ep_gpio, 0);
 
+       err = reset_control_assert(rockchip->aclk_rst);
+       if (err) {
+               dev_err(dev, "assert aclk_rst err %d\n", err);
+               return err;
+       }
+
+       err = reset_control_assert(rockchip->pclk_rst);
+       if (err) {
+               dev_err(dev, "assert pclk_rst err %d\n", err);
+               return err;
+       }
+
+       err = reset_control_assert(rockchip->pm_rst);
+       if (err) {
+               dev_err(dev, "assert pm_rst err %d\n", err);
+               return err;
+       }
+
+       udelay(10);
+
+       err = reset_control_deassert(rockchip->pm_rst);
+       if (err) {
+               dev_err(dev, "deassert pm_rst err %d\n", err);
+               return err;
+       }
+
+       err = reset_control_deassert(rockchip->aclk_rst);
+       if (err) {
+               dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err);
+               return err;
+       }
+
+       err = reset_control_deassert(rockchip->pclk_rst);
+       if (err) {
+               dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err);
+               return err;
+       }
+
        err = phy_init(rockchip->phy);
        if (err < 0) {
                dev_err(dev, "fail to init phy, err %d\n", err);
@@ -781,6 +822,27 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
                return PTR_ERR(rockchip->pipe_rst);
        }
 
+       rockchip->pm_rst = devm_reset_control_get(dev, "pm");
+       if (IS_ERR(rockchip->pm_rst)) {
+               if (PTR_ERR(rockchip->pm_rst) != -EPROBE_DEFER)
+                       dev_err(dev, "missing pm reset property in node\n");
+               return PTR_ERR(rockchip->pm_rst);
+       }
+
+       rockchip->pclk_rst = devm_reset_control_get(dev, "pclk");
+       if (IS_ERR(rockchip->pclk_rst)) {
+               if (PTR_ERR(rockchip->pclk_rst) != -EPROBE_DEFER)
+                       dev_err(dev, "missing pclk reset property in node\n");
+               return PTR_ERR(rockchip->pclk_rst);
+       }
+
+       rockchip->aclk_rst = devm_reset_control_get(dev, "aclk");
+       if (IS_ERR(rockchip->aclk_rst)) {
+               if (PTR_ERR(rockchip->aclk_rst) != -EPROBE_DEFER)
+                       dev_err(dev, "missing aclk reset property in node\n");
+               return PTR_ERR(rockchip->aclk_rst);
+       }
+
        rockchip->ep_gpio = devm_gpiod_get(dev, "ep", GPIOD_OUT_HIGH);
        if (IS_ERR(rockchip->ep_gpio)) {
                dev_err(dev, "missing ep-gpios property in node\n");
index bfdd0744b686abdb6d76fafd5132da1c294a7f6c..ad70507cfb566a2291498d4ba723e1a5a4aebd3c 100644 (file)
@@ -610,6 +610,7 @@ static int msi_verify_entries(struct pci_dev *dev)
  * msi_capability_init - configure device's MSI capability structure
  * @dev: pointer to the pci_dev data structure of MSI device function
  * @nvec: number of interrupts to allocate
+ * @affinity: flag to indicate cpu irq affinity mask should be set
  *
  * Setup the MSI capability structure of the device with the requested
  * number of interrupts.  A return value of zero indicates the successful
@@ -752,6 +753,7 @@ static void msix_program_entries(struct pci_dev *dev,
  * @dev: pointer to the pci_dev data structure of MSI-X device function
  * @entries: pointer to an array of struct msix_entry entries
  * @nvec: number of @entries
+ * @affinity: flag to indicate cpu irq affinity mask should be set
  *
  * Setup the MSI-X capability structure of device function with a
  * single MSI-X irq. A return of zero indicates the successful setup of
index 55f453de562ee63b8e53ab90cf6b671ef676c2a8..c7f3408e31487ef2db339233c61a4e66d15bb07d 100644 (file)
@@ -29,6 +29,11 @@ static int mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state)
        return intel_mid_pci_set_power_state(pdev, state);
 }
 
+static pci_power_t mid_pci_get_power_state(struct pci_dev *pdev)
+{
+       return intel_mid_pci_get_power_state(pdev);
+}
+
 static pci_power_t mid_pci_choose_state(struct pci_dev *pdev)
 {
        return PCI_D3hot;
@@ -52,6 +57,7 @@ static bool mid_pci_need_resume(struct pci_dev *dev)
 static struct pci_platform_pm_ops mid_pci_platform_pm = {
        .is_manageable  = mid_pci_power_manageable,
        .set_state      = mid_pci_set_power_state,
+       .get_state      = mid_pci_get_power_state,
        .choose_state   = mid_pci_choose_state,
        .sleep_wake     = mid_pci_sleep_wake,
        .run_wake       = mid_pci_run_wake,
index db553dc22c8e0fca49ad98ff2f9fd3111e18918a..2b6a59266689b486c9fe42355af77868086a35b1 100644 (file)
@@ -307,20 +307,6 @@ out:
        return 0;
 }
 
-static struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
-{
-       while (1) {
-               if (!pci_is_pcie(dev))
-                       break;
-               if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
-                       return dev;
-               if (!dev->bus->self)
-                       break;
-               dev = dev->bus->self;
-       }
-       return NULL;
-}
-
 static int find_aer_device_iter(struct device *device, void *data)
 {
        struct pcie_device **result = data;
index ab002671fa60e14b83568a24d2cf504687f391f9..104c46d531218874044775b19e68f2ba85c85714 100644 (file)
@@ -1439,6 +1439,21 @@ static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp)
                dev_warn(&dev->dev, "PCI-X settings not supported\n");
 }
 
+static bool pcie_root_rcb_set(struct pci_dev *dev)
+{
+       struct pci_dev *rp = pcie_find_root_port(dev);
+       u16 lnkctl;
+
+       if (!rp)
+               return false;
+
+       pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &lnkctl);
+       if (lnkctl & PCI_EXP_LNKCTL_RCB)
+               return true;
+
+       return false;
+}
+
 static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
 {
        int pos;
@@ -1468,9 +1483,20 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
                        ~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
 
        /* Initialize Link Control Register */
-       if (pcie_cap_has_lnkctl(dev))
+       if (pcie_cap_has_lnkctl(dev)) {
+
+               /*
+                * If the Root Port supports Read Completion Boundary of
+                * 128, set RCB to 128.  Otherwise, clear it.
+                */
+               hpp->pci_exp_lnkctl_and |= PCI_EXP_LNKCTL_RCB;
+               hpp->pci_exp_lnkctl_or &= ~PCI_EXP_LNKCTL_RCB;
+               if (pcie_root_rcb_set(dev))
+                       hpp->pci_exp_lnkctl_or |= PCI_EXP_LNKCTL_RCB;
+
                pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
                        ~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
+       }
 
        /* Find Advanced Error Reporting Enhanced Capability */
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
index 66c4d8f4223377d6bb54849d7794fc8172b1e0a2..9526e341988ba469cdfbe48ff23591e3180d1119 100644 (file)
@@ -121,6 +121,14 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
                return -EINVAL;
        }
 
+       /*
+        * If we have a shadow copy in RAM, the PCI device doesn't respond
+        * to the shadow range, so we don't need to claim it, and upstream
+        * bridges don't need to route the range to the device.
+        */
+       if (res->flags & IORESOURCE_ROM_SHADOW)
+               return 0;
+
        root = pci_find_parent_resource(dev, res);
        if (!root) {
                dev_info(&dev->dev, "can't claim BAR %d %pR: no compatible bridge window\n",
index 153f3122283deb9fa4260c0e1da0c443a5fde2c0..b6b316de055c7129648904cbdae92cafb593e8dd 100644 (file)
@@ -107,7 +107,7 @@ int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt,
 
                ret = regulator_enable(r->reg);
        } else {
-               regulator_disable(r->reg);
+               ret = regulator_disable(r->reg);
        }
        if (ret == 0)
                r->on = on;
index c2ac7646b99f4b50cfec9a2d899ba53c55c238c3..a8ac4bcef2c04ad19247a27764f798726bc68892 100644 (file)
@@ -1011,7 +1011,7 @@ xgene_pmu_dev_ctx *acpi_get_pmu_hw_inf(struct xgene_pmu *xgene_pmu,
        rc = acpi_dev_get_resources(adev, &resource_list,
                                    acpi_pmu_dev_add_resource, &res);
        acpi_dev_free_resource_list(&resource_list);
-       if (rc < 0 || IS_ERR(&res)) {
+       if (rc < 0) {
                dev_err(dev, "PMU type %d: No resource address found\n", type);
                goto err;
        }
index 32ae78c8ca17655d877a66952d098d56a0eacf3c..c85fb0b59729de9febdbbcbeec59e2bcd80d1a2d 100644 (file)
@@ -198,7 +198,8 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev)
        } else {
                int ret;
 
-               ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
+               ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy",
+                                       "ohci-da8xx");
                if (ret)
                        dev_warn(dev, "Failed to create usb11 phy lookup\n");
                ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy",
@@ -216,7 +217,7 @@ static int da8xx_usb_phy_remove(struct platform_device *pdev)
 
        if (!pdev->dev.of_node) {
                phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx");
-               phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
+               phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx");
        }
 
        return 0;
index a2b4c6b58aea66d0b06cb153359ea3c31d4f6e66..6904633cad687d114cf19eb3292aba9896feb408 100644 (file)
@@ -249,21 +249,10 @@ err_refclk:
 static int rockchip_pcie_phy_exit(struct phy *phy)
 {
        struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy);
-       int err = 0;
 
        clk_disable_unprepare(rk_phy->clk_pciephy_ref);
 
-       err = reset_control_deassert(rk_phy->phy_rst);
-       if (err) {
-               dev_err(&phy->dev, "deassert phy_rst err %d\n", err);
-               goto err_reset;
-       }
-
-       return err;
-
-err_reset:
-       clk_prepare_enable(rk_phy->clk_pciephy_ref);
-       return err;
+       return 0;
 }
 
 static const struct phy_ops ops = {
index b9342a2af7b3666f86471d649bd134a4baa9ff13..fec34f5213c46739b5231f34bfe628731c231a9a 100644 (file)
@@ -264,7 +264,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
                return ret;
        }
 
-       if (data->cfg->enable_pmu_unk1) {
+       if (phy->pmu && data->cfg->enable_pmu_unk1) {
                val = readl(phy->pmu + REG_PMU_UNK1);
                writel(val & ~2, phy->pmu + REG_PMU_UNK1);
        }
index 87e6334eab9309f85e8cb5308f96dec54de7f495..547ca7b3f09850ce0f0928b4fe0a26cbcaab14d2 100644 (file)
@@ -459,8 +459,6 @@ static int twl4030_phy_power_off(struct phy *phy)
        struct twl4030_usb *twl = phy_get_drvdata(phy);
 
        dev_dbg(twl->dev, "%s\n", __func__);
-       pm_runtime_mark_last_busy(twl->dev);
-       pm_runtime_put_autosuspend(twl->dev);
 
        return 0;
 }
@@ -472,6 +470,8 @@ static int twl4030_phy_power_on(struct phy *phy)
        dev_dbg(twl->dev, "%s\n", __func__);
        pm_runtime_get_sync(twl->dev);
        schedule_delayed_work(&twl->id_workaround_work, HZ);
+       pm_runtime_mark_last_busy(twl->dev);
+       pm_runtime_put_autosuspend(twl->dev);
 
        return 0;
 }
index e1ab864e1a7f06f7600a435ed4ed80e8513d5336..87b46390b69597a3299143f3ec4e0ab282475718 100644 (file)
@@ -26,7 +26,7 @@
 
 #define ASPEED_G5_NR_PINS 228
 
-#define COND1          SIG_DESC_BIT(SCU90, 6, 0)
+#define COND1          { SCU90, BIT(6), 0, 0 }
 #define COND2          { SCU94, GENMASK(1, 0), 0, 0 }
 
 #define B14 0
@@ -151,21 +151,21 @@ FUNC_GROUP_DECL(GPID0, F19, E21);
 
 #define GPID2_DESC      SIG_DESC_SET(SCU8C, 9)
 
-#define D20 26
+#define F20 26
 SIG_EXPR_LIST_DECL_SINGLE(SD2DAT0, SD2, SD2_DESC);
 SIG_EXPR_DECL(GPID2IN, GPID2, GPID2_DESC);
 SIG_EXPR_DECL(GPID2IN, GPID, GPID_DESC);
 SIG_EXPR_LIST_DECL_DUAL(GPID2IN, GPID2, GPID);
-MS_PIN_DECL(D20, GPIOD2, SD2DAT0, GPID2IN);
+MS_PIN_DECL(F20, GPIOD2, SD2DAT0, GPID2IN);
 
-#define D21 27
+#define D20 27
 SIG_EXPR_LIST_DECL_SINGLE(SD2DAT1, SD2, SD2_DESC);
 SIG_EXPR_DECL(GPID2OUT, GPID2, GPID2_DESC);
 SIG_EXPR_DECL(GPID2OUT, GPID, GPID_DESC);
 SIG_EXPR_LIST_DECL_DUAL(GPID2OUT, GPID2, GPID);
-MS_PIN_DECL(D21, GPIOD3, SD2DAT1, GPID2OUT);
+MS_PIN_DECL(D20, GPIOD3, SD2DAT1, GPID2OUT);
 
-FUNC_GROUP_DECL(GPID2, D20, D21);
+FUNC_GROUP_DECL(GPID2, F20, D20);
 
 #define GPIE_DESC      SIG_DESC_SET(HW_STRAP1, 21)
 #define GPIE0_DESC     SIG_DESC_SET(SCU8C, 12)
@@ -182,28 +182,88 @@ SIG_EXPR_LIST_DECL_SINGLE(NDCD3, NDCD3, SIG_DESC_SET(SCU80, 17));
 SIG_EXPR_DECL(GPIE0OUT, GPIE0, GPIE0_DESC);
 SIG_EXPR_DECL(GPIE0OUT, GPIE, GPIE_DESC);
 SIG_EXPR_LIST_DECL_DUAL(GPIE0OUT, GPIE0, GPIE);
-MS_PIN_DECL(C20, GPIE0, NDCD3, GPIE0OUT);
+MS_PIN_DECL(C20, GPIOE1, NDCD3, GPIE0OUT);
 
 FUNC_GROUP_DECL(GPIE0, B20, C20);
 
-#define SPI1_DESC      SIG_DESC_SET(HW_STRAP1, 13)
+#define SPI1_DESC              { HW_STRAP1, GENMASK(13, 12), 1, 0 }
+#define SPI1DEBUG_DESC         { HW_STRAP1, GENMASK(13, 12), 2, 0 }
+#define SPI1PASSTHRU_DESC      { HW_STRAP1, GENMASK(13, 12), 3, 0 }
+
 #define C18 64
-SIG_EXPR_LIST_DECL_SINGLE(SYSCS, SPI1, COND1, SPI1_DESC);
+SIG_EXPR_DECL(SYSCS, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSCS, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSCS, SPI1DEBUG, SPI1PASSTHRU);
 SS_PIN_DECL(C18, GPIOI0, SYSCS);
 
 #define E15 65
-SIG_EXPR_LIST_DECL_SINGLE(SYSCK, SPI1, COND1, SPI1_DESC);
+SIG_EXPR_DECL(SYSCK, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSCK, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSCK, SPI1DEBUG, SPI1PASSTHRU);
 SS_PIN_DECL(E15, GPIOI1, SYSCK);
 
-#define A14 66
-SIG_EXPR_LIST_DECL_SINGLE(SYSMOSI, SPI1, COND1, SPI1_DESC);
-SS_PIN_DECL(A14, GPIOI2, SYSMOSI);
+#define B16 66
+SIG_EXPR_DECL(SYSMOSI, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSMOSI, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSMOSI, SPI1DEBUG, SPI1PASSTHRU);
+SS_PIN_DECL(B16, GPIOI2, SYSMOSI);
 
 #define C16 67
-SIG_EXPR_LIST_DECL_SINGLE(SYSMISO, SPI1, COND1, SPI1_DESC);
+SIG_EXPR_DECL(SYSMISO, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSMISO, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSMISO, SPI1DEBUG, SPI1PASSTHRU);
 SS_PIN_DECL(C16, GPIOI3, SYSMISO);
 
-FUNC_GROUP_DECL(SPI1, C18, E15, A14, C16);
+#define VB_DESC        SIG_DESC_SET(HW_STRAP1, 5)
+
+#define B15 68
+SIG_EXPR_DECL(SPI1CS0, SPI1, COND1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1CS0, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1CS0, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1CS0, SIG_EXPR_PTR(SPI1CS0, SPI1),
+                           SIG_EXPR_PTR(SPI1CS0, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1CS0, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBCS, VGABIOSROM, COND1, VB_DESC);
+MS_PIN_DECL(B15, GPIOI4, SPI1CS0, VBCS);
+
+#define C15 69
+SIG_EXPR_DECL(SPI1CK, SPI1, COND1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1CK, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1CK, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1CK, SIG_EXPR_PTR(SPI1CK, SPI1),
+                           SIG_EXPR_PTR(SPI1CK, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1CK, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBCK, VGABIOSROM, COND1, VB_DESC);
+MS_PIN_DECL(C15, GPIOI5, SPI1CK, VBCK);
+
+#define A14 70
+SIG_EXPR_DECL(SPI1MOSI, SPI1, COND1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1MOSI, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1MOSI, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1MOSI, SIG_EXPR_PTR(SPI1MOSI, SPI1),
+                           SIG_EXPR_PTR(SPI1MOSI, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1MOSI, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBMOSI, VGABIOSROM, COND1, VB_DESC);
+MS_PIN_DECL(A14, GPIOI6, SPI1MOSI, VBMOSI);
+
+#define A15 71
+SIG_EXPR_DECL(SPI1MISO, SPI1, COND1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1MISO, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1MISO, SPI1PASSTHRU, COND1, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1MISO, SIG_EXPR_PTR(SPI1MISO, SPI1),
+                           SIG_EXPR_PTR(SPI1MISO, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1MISO, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBMISO, VGABIOSROM, COND1, VB_DESC);
+MS_PIN_DECL(A15, GPIOI7, SPI1MISO, VBMISO);
+
+FUNC_GROUP_DECL(SPI1, B15, C15, A14, A15);
+FUNC_GROUP_DECL(SPI1DEBUG, C18, E15, B16, C16, B15, C15, A14, A15);
+FUNC_GROUP_DECL(SPI1PASSTHRU, C18, E15, B16, C16, B15, C15, A14, A15);
+FUNC_GROUP_DECL(VGABIOSROM, B15, C15, A14, A15);
+
+#define R2 72
+SIG_EXPR_LIST_DECL_SINGLE(SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8));
+SS_PIN_DECL(R2, GPIOJ0, SGPMCK);
 
 #define L2 73
 SIG_EXPR_LIST_DECL_SINGLE(SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9));
@@ -580,6 +640,7 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(A12),
        ASPEED_PINCTRL_PIN(A13),
        ASPEED_PINCTRL_PIN(A14),
+       ASPEED_PINCTRL_PIN(A15),
        ASPEED_PINCTRL_PIN(A2),
        ASPEED_PINCTRL_PIN(A3),
        ASPEED_PINCTRL_PIN(A4),
@@ -592,6 +653,8 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(B12),
        ASPEED_PINCTRL_PIN(B13),
        ASPEED_PINCTRL_PIN(B14),
+       ASPEED_PINCTRL_PIN(B15),
+       ASPEED_PINCTRL_PIN(B16),
        ASPEED_PINCTRL_PIN(B2),
        ASPEED_PINCTRL_PIN(B20),
        ASPEED_PINCTRL_PIN(B3),
@@ -603,6 +666,7 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(C12),
        ASPEED_PINCTRL_PIN(C13),
        ASPEED_PINCTRL_PIN(C14),
+       ASPEED_PINCTRL_PIN(C15),
        ASPEED_PINCTRL_PIN(C16),
        ASPEED_PINCTRL_PIN(C18),
        ASPEED_PINCTRL_PIN(C2),
@@ -614,7 +678,6 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(D10),
        ASPEED_PINCTRL_PIN(D2),
        ASPEED_PINCTRL_PIN(D20),
-       ASPEED_PINCTRL_PIN(D21),
        ASPEED_PINCTRL_PIN(D4),
        ASPEED_PINCTRL_PIN(D5),
        ASPEED_PINCTRL_PIN(D6),
@@ -630,6 +693,7 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(E7),
        ASPEED_PINCTRL_PIN(E9),
        ASPEED_PINCTRL_PIN(F19),
+       ASPEED_PINCTRL_PIN(F20),
        ASPEED_PINCTRL_PIN(F9),
        ASPEED_PINCTRL_PIN(H20),
        ASPEED_PINCTRL_PIN(L1),
@@ -691,11 +755,14 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = {
        ASPEED_PINCTRL_GROUP(RMII2),
        ASPEED_PINCTRL_GROUP(SD1),
        ASPEED_PINCTRL_GROUP(SPI1),
+       ASPEED_PINCTRL_GROUP(SPI1DEBUG),
+       ASPEED_PINCTRL_GROUP(SPI1PASSTHRU),
        ASPEED_PINCTRL_GROUP(TIMER4),
        ASPEED_PINCTRL_GROUP(TIMER5),
        ASPEED_PINCTRL_GROUP(TIMER6),
        ASPEED_PINCTRL_GROUP(TIMER7),
        ASPEED_PINCTRL_GROUP(TIMER8),
+       ASPEED_PINCTRL_GROUP(VGABIOSROM),
 };
 
 static const struct aspeed_pin_function aspeed_g5_functions[] = {
@@ -733,11 +800,14 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = {
        ASPEED_PINCTRL_FUNC(RMII2),
        ASPEED_PINCTRL_FUNC(SD1),
        ASPEED_PINCTRL_FUNC(SPI1),
+       ASPEED_PINCTRL_FUNC(SPI1DEBUG),
+       ASPEED_PINCTRL_FUNC(SPI1PASSTHRU),
        ASPEED_PINCTRL_FUNC(TIMER4),
        ASPEED_PINCTRL_FUNC(TIMER5),
        ASPEED_PINCTRL_FUNC(TIMER6),
        ASPEED_PINCTRL_FUNC(TIMER7),
        ASPEED_PINCTRL_FUNC(TIMER8),
+       ASPEED_PINCTRL_FUNC(VGABIOSROM),
 };
 
 static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = {
index 0391f9f13f3e6cb0d15334e27f0d6d92733702a7..49aeba91253198c644794c23cb4877368f6905ad 100644 (file)
@@ -166,13 +166,9 @@ static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
                                bool enable, struct regmap *map)
 {
        int i;
-       bool ret;
-
-       ret = aspeed_sig_expr_eval(expr, enable, map);
-       if (ret)
-               return ret;
 
        for (i = 0; i < expr->ndescs; i++) {
+               bool ret;
                const struct aspeed_sig_desc *desc = &expr->descs[i];
                u32 pattern = enable ? desc->enable : desc->disable;
 
@@ -199,12 +195,18 @@ static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
 static bool aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr,
                                   struct regmap *map)
 {
+       if (aspeed_sig_expr_eval(expr, true, map))
+               return true;
+
        return aspeed_sig_expr_set(expr, true, map);
 }
 
 static bool aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
                                    struct regmap *map)
 {
+       if (!aspeed_sig_expr_eval(expr, true, map))
+               return true;
+
        return aspeed_sig_expr_set(expr, false, map);
 }
 
index 7f77007163985762abc6110f282eec762bdc8a92..5d1e505c3c63d76a85af0dcb7051b9a3da15c2e5 100644 (file)
@@ -844,6 +844,6 @@ static struct platform_driver iproc_gpio_driver = {
 
 static int __init iproc_gpio_init(void)
 {
-       return platform_driver_probe(&iproc_gpio_driver, iproc_gpio_probe);
+       return platform_driver_register(&iproc_gpio_driver);
 }
 arch_initcall_sync(iproc_gpio_init);
index 35783db1c10bad5f50bb8ac41a59307dc97b852e..c8deb8be1da785fd15d8f5182b3b19143ca3c33f 100644 (file)
@@ -741,6 +741,6 @@ static struct platform_driver nsp_gpio_driver = {
 
 static int __init nsp_gpio_init(void)
 {
-       return platform_driver_probe(&nsp_gpio_driver, nsp_gpio_probe);
+       return platform_driver_register(&nsp_gpio_driver);
 }
 arch_initcall_sync(nsp_gpio_init);
index 47613201269af42dd3fff670c92008333bf0adf0..79c4e14a5a75e94fec9315588896bcfe9a104c11 100644 (file)
@@ -687,6 +687,7 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
        if (!info->functions)
                return -ENOMEM;
 
+       info->group_index = 0;
        if (flat_funcs) {
                info->ngroups = of_get_child_count(np);
        } else {
index d22a9fe2e6dfc36d63f9e493b61f2f35c2e21f97..71bbeb9321bad587504bf5ca4f4c889019b4b9f4 100644 (file)
@@ -1808,6 +1808,8 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
                return PTR_ERR(vg->pctl_dev);
        }
 
+       raw_spin_lock_init(&vg->lock);
+
        ret = byt_gpio_probe(vg);
        if (ret) {
                pinctrl_unregister(vg->pctl_dev);
@@ -1815,7 +1817,6 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, vg);
-       raw_spin_lock_init(&vg->lock);
        pm_runtime_enable(&pdev->dev);
 
        return 0;
index 30389f4ccab4935c20ddcbed2c5a543e77d33fc5..c43b1e9a06aff0ba3fa94f49967ca4259ed77ced 100644 (file)
@@ -1652,12 +1652,15 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int chv_pinctrl_suspend(struct device *dev)
+static int chv_pinctrl_suspend_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
+       unsigned long flags;
        int i;
 
+       raw_spin_lock_irqsave(&chv_lock, flags);
+
        pctrl->saved_intmask = readl(pctrl->regs + CHV_INTMASK);
 
        for (i = 0; i < pctrl->community->npins; i++) {
@@ -1678,15 +1681,20 @@ static int chv_pinctrl_suspend(struct device *dev)
                ctx->padctrl1 = readl(reg);
        }
 
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
+
        return 0;
 }
 
-static int chv_pinctrl_resume(struct device *dev)
+static int chv_pinctrl_resume_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
+       unsigned long flags;
        int i;
 
+       raw_spin_lock_irqsave(&chv_lock, flags);
+
        /*
         * Mask all interrupts before restoring per-pin configuration
         * registers because we don't know in which state BIOS left them
@@ -1731,12 +1739,15 @@ static int chv_pinctrl_resume(struct device *dev)
        chv_writel(0xffff, pctrl->regs + CHV_INTSTAT);
        chv_writel(pctrl->saved_intmask, pctrl->regs + CHV_INTMASK);
 
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
+
        return 0;
 }
 #endif
 
 static const struct dev_pm_ops chv_pinctrl_pm_ops = {
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend, chv_pinctrl_resume)
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend_noirq,
+                                     chv_pinctrl_resume_noirq)
 };
 
 static const struct acpi_device_id chv_pinctrl_acpi_match[] = {
index 63387a40b973a417d6dd00ec9fe952413465b159..01443762e57055b88ea9f1accb0cf6e10eda2978 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
+#include "../core.h"
 #include "pinctrl-intel.h"
 
 /* Offset from regs */
@@ -1056,6 +1057,26 @@ int intel_pinctrl_remove(struct platform_device *pdev)
 EXPORT_SYMBOL_GPL(intel_pinctrl_remove);
 
 #ifdef CONFIG_PM_SLEEP
+static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin)
+{
+       const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
+
+       if (!pd || !intel_pad_usable(pctrl, pin))
+               return false;
+
+       /*
+        * Only restore the pin if it is actually in use by the kernel (or
+        * by userspace). It is possible that some pins are used by the
+        * BIOS during resume and those are not always locked down so leave
+        * them alone.
+        */
+       if (pd->mux_owner || pd->gpio_owner ||
+           gpiochip_line_is_irq(&pctrl->chip, pin))
+               return true;
+
+       return false;
+}
+
 int intel_pinctrl_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -1069,7 +1090,7 @@ int intel_pinctrl_suspend(struct device *dev)
                const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
                u32 val;
 
-               if (!intel_pad_usable(pctrl, desc->number))
+               if (!intel_pinctrl_should_save(pctrl, desc->number))
                        continue;
 
                val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0));
@@ -1130,7 +1151,7 @@ int intel_pinctrl_resume(struct device *dev)
                void __iomem *padcfg;
                u32 val;
 
-               if (!intel_pad_usable(pctrl, desc->number))
+               if (!intel_pinctrl_should_save(pctrl, desc->number))
                        continue;
 
                padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0);
index 99da4cf91031b49757cc24735057b72c3d4f760e..b7bb371679692e5dd76186be130ed4b4a6a86cb3 100644 (file)
@@ -1512,7 +1512,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
        if (info->irqmux_base || gpio_irq > 0) {
                err = gpiochip_irqchip_add(&bank->gpio_chip, &st_gpio_irqchip,
                                           0, handle_simple_irq,
-                                          IRQ_TYPE_LEVEL_LOW);
+                                          IRQ_TYPE_NONE);
                if (err) {
                        gpiochip_remove(&bank->gpio_chip);
                        dev_info(dev, "could not add irqchip\n");
index 200667f08c373eb027f2bcc4253f564563586e96..efc43711ff5cbcff2c94838e06ead49623ab9118 100644 (file)
@@ -1092,9 +1092,11 @@ int stm32_pctl_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       ret = stm32_pctrl_dt_setup_irq(pdev, pctl);
-       if (ret)
-               return ret;
+       if (of_find_property(np, "interrupt-parent", NULL)) {
+               ret = stm32_pctrl_dt_setup_irq(pdev, pctl);
+               if (ret)
+                       return ret;
+       }
 
        for_each_child_of_node(np, child)
                if (of_property_read_bool(child, "gpio-controller"))
index 07462d79d04000685c946a19a9cef1d90526400d..1aba2c74160eb5c51ce49dd679de2dd0090fe2dd 100644 (file)
@@ -309,7 +309,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
                 * much memory to the process.
                 */
                down_read(&current->mm->mmap_sem);
-               ret = get_user_pages(address, 1, !is_write, 0, &page, NULL);
+               ret = get_user_pages(address, 1, is_write ? 0 : FOLL_WRITE,
+                               &page, NULL);
                up_read(&current->mm->mmap_sem);
                if (ret < 0)
                        break;
index 81b8dcca8891dc00ca5d0cb48c28329d25e70887..b8a21d7b25d4c34e4042caf624ac4c86211c11d0 100644 (file)
@@ -576,6 +576,7 @@ config ASUS_WMI
 config ASUS_NB_WMI
        tristate "Asus Notebook WMI Driver"
        depends on ASUS_WMI
+       depends on SERIO_I8042 || SERIO_I8042 = n
        ---help---
          This is a driver for newer Asus notebooks. It adds extra features
          like wireless radio and bluetooth control, leds, hotkeys, backlight...
index d1a091b93192c7dc4a20d8dbf9901d65d918e1e1..a7614fc542b52aaaa4f58d91ea43bd9625e8de32 100644 (file)
@@ -933,6 +933,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"),
                },
        },
+       {
+               .ident = "Lenovo Yoga 900",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "VIUU4"),
+               },
+       },
+       {
+               .ident = "Lenovo YOGA 910-13IKB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"),
+               },
+       },
        {}
 };
 
index ed5874217ee76cf4364d8bbd6f8e49f26e19c215..12dbb50633761b40253adff49f0c3881b40fed90 100644 (file)
@@ -264,7 +264,7 @@ check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
                return AE_OK;
 
        if (acpi_match_device_ids(dev, ids) == 0)
-               if (acpi_create_platform_device(dev))
+               if (acpi_create_platform_device(dev, NULL))
                        dev_info(&dev->dev,
                                 "intel-hid: created platform device\n");
 
index 146d02f8c9bc01c99c791bb45ba8df77ce7bb64b..78080763df51768f04548e1627d3baded9bbac14 100644 (file)
@@ -164,7 +164,7 @@ check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv)
                return AE_OK;
 
        if (acpi_match_device_ids(dev, ids) == 0)
-               if (acpi_create_platform_device(dev))
+               if (acpi_create_platform_device(dev, NULL))
                        dev_info(&dev->dev,
                                 "intel-vbtn: created platform device\n");
 
index feac4576b837101c35cf7442ca07ee47496633fe..2df07ee8f3c33e9f5e92fd776554bd44e614e836 100644 (file)
 #include <linux/acpi.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <linux/dmi.h>
 
 MODULE_AUTHOR("Azael Avalos");
 MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver");
 MODULE_LICENSE("GPL");
 
-#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
+#define WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
 
-MODULE_ALIAS("wmi:"TOSHIBA_WMI_EVENT_GUID);
+MODULE_ALIAS("wmi:"WMI_EVENT_GUID);
 
 static struct input_dev *toshiba_wmi_input_dev;
 
@@ -63,6 +64,16 @@ static void toshiba_wmi_notify(u32 value, void *context)
        kfree(response.pointer);
 }
 
+static struct dmi_system_id toshiba_wmi_dmi_table[] __initdata = {
+       {
+               .ident = "Toshiba laptop",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               },
+       },
+       {}
+};
+
 static int __init toshiba_wmi_input_setup(void)
 {
        acpi_status status;
@@ -81,7 +92,7 @@ static int __init toshiba_wmi_input_setup(void)
        if (err)
                goto err_free_dev;
 
-       status = wmi_install_notify_handler(TOSHIBA_WMI_EVENT_GUID,
+       status = wmi_install_notify_handler(WMI_EVENT_GUID,
                                            toshiba_wmi_notify, NULL);
        if (ACPI_FAILURE(status)) {
                err = -EIO;
@@ -95,7 +106,7 @@ static int __init toshiba_wmi_input_setup(void)
        return 0;
 
  err_remove_notifier:
-       wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID);
+       wmi_remove_notify_handler(WMI_EVENT_GUID);
  err_free_keymap:
        sparse_keymap_free(toshiba_wmi_input_dev);
  err_free_dev:
@@ -105,7 +116,7 @@ static int __init toshiba_wmi_input_setup(void)
 
 static void toshiba_wmi_input_destroy(void)
 {
-       wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID);
+       wmi_remove_notify_handler(WMI_EVENT_GUID);
        sparse_keymap_free(toshiba_wmi_input_dev);
        input_unregister_device(toshiba_wmi_input_dev);
 }
@@ -114,7 +125,8 @@ static int __init toshiba_wmi_init(void)
 {
        int ret;
 
-       if (!wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+       if (!wmi_has_guid(WMI_EVENT_GUID) ||
+           !dmi_check_system(toshiba_wmi_dmi_table))
                return -ENODEV;
 
        ret = toshiba_wmi_input_setup();
@@ -130,7 +142,7 @@ static int __init toshiba_wmi_init(void)
 
 static void __exit toshiba_wmi_exit(void)
 {
-       if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+       if (wmi_has_guid(WMI_EVENT_GUID))
                toshiba_wmi_input_destroy();
 }
 
index 381871b2bb46ba3439b4ca4bb7ace7277233b372..9d5bd7d5c610b1736eb5698b3b410de6f2c746ed 100644 (file)
@@ -474,6 +474,7 @@ static int meson_pwm_probe(struct platform_device *pdev)
        if (IS_ERR(meson->base))
                return PTR_ERR(meson->base);
 
+       spin_lock_init(&meson->lock);
        meson->chip.dev = &pdev->dev;
        meson->chip.ops = &meson_pwm_ops;
        meson->chip.base = -1;
index 0296d8178ae29d509306670c9bb85147c50f0633..a813239300c3d46bba1320caac77ec7adc8363a8 100644 (file)
@@ -425,6 +425,8 @@ void pwmchip_sysfs_unexport_children(struct pwm_chip *chip)
                if (test_bit(PWMF_EXPORTED, &pwm->flags))
                        pwm_unexport_child(parent, pwm);
        }
+
+       put_device(parent);
 }
 
 static int __init pwm_sysfs_init(void)
index 436dfe871d3230436adb301ccec42563063dfb0b..9013a585507e8a80b4580c084445ec7bbde6e04c 100644 (file)
@@ -892,7 +892,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
                down_read(&current->mm->mmap_sem);
                pinned = get_user_pages(
                                (unsigned long)xfer->loc_addr & PAGE_MASK,
-                               nr_pages, dir == DMA_FROM_DEVICE, 0,
+                               nr_pages,
+                               dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
                                page_list, NULL);
                up_read(&current->mm->mmap_sem);
 
index 67426c0477d34b2b5805826664bbc4074acfe591..5c1519b229e0e5cd718e4694cf0b27cde1c73f6d 100644 (file)
@@ -2754,7 +2754,7 @@ static int _regulator_set_voltage_time(struct regulator_dev *rdev,
                ramp_delay = rdev->desc->ramp_delay;
 
        if (ramp_delay == 0) {
-               rdev_warn(rdev, "ramp_delay not set\n");
+               rdev_dbg(rdev, "ramp_delay not set\n");
                return 0;
        }
 
index 3314bf299a51f54fcff2fed6f600ae33eaf44a57..fb44d5215e30c8573b8eef9ad751367ef4e23e81 100644 (file)
@@ -120,7 +120,7 @@ static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = {
 static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev)
 {
        struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev);
-       int id = rdev->desc->id - RK808_ID_DCDC1;
+       int id = rdev_get_id(rdev);
        struct gpio_desc *gpio = pdata->dvs_gpio[id];
        unsigned int val;
        int ret;
@@ -193,7 +193,7 @@ static int rk808_buck1_2_set_voltage_sel(struct regulator_dev *rdev,
                                         unsigned sel)
 {
        struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev);
-       int id = rdev->desc->id - RK808_ID_DCDC1;
+       int id = rdev_get_id(rdev);
        struct gpio_desc *gpio = pdata->dvs_gpio[id];
        unsigned int reg = rdev->desc->vsel_reg;
        unsigned old_sel;
@@ -232,7 +232,7 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev,
                                       unsigned int new_selector)
 {
        struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev);
-       int id = rdev->desc->id - RK808_ID_DCDC1;
+       int id = rdev_get_id(rdev);
        struct gpio_desc *gpio = pdata->dvs_gpio[id];
 
        /* if there is no dvs1/2 pin, we don't need wait extra time here. */
@@ -245,8 +245,7 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev,
 static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
 {
        unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US;
-       unsigned int reg = rk808_buck_config_regs[rdev->desc->id -
-                                                 RK808_ID_DCDC1];
+       unsigned int reg = rk808_buck_config_regs[rdev_get_id(rdev)];
 
        switch (ramp_delay) {
        case 1 ... 2000:
index 8b2558e7363e249726336472729350f879519e94..968c3ae4535cf2f2b6fc26c54c02e773b659c104 100644 (file)
@@ -154,7 +154,7 @@ const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = {
        UNIPHIER_RESET_END,
 };
 
-const struct uniphier_reset_data uniphier_pro5_mio_reset_data[] = {
+const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = {
        UNIPHIER_MIO_RESET_SD(0, 0),
        UNIPHIER_MIO_RESET_SD(1, 1),
        UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
@@ -360,7 +360,7 @@ static const struct of_device_id uniphier_reset_match[] = {
                .compatible = "socionext,uniphier-ld20-reset",
                .data = uniphier_ld20_sys_reset_data,
        },
-       /* Media I/O reset */
+       /* Media I/O reset, SD reset */
        {
                .compatible = "socionext,uniphier-sld3-mio-reset",
                .data = uniphier_sld3_mio_reset_data,
@@ -378,20 +378,20 @@ static const struct of_device_id uniphier_reset_match[] = {
                .data = uniphier_sld3_mio_reset_data,
        },
        {
-               .compatible = "socionext,uniphier-pro5-mio-reset",
-               .data = uniphier_pro5_mio_reset_data,
+               .compatible = "socionext,uniphier-pro5-sd-reset",
+               .data = uniphier_pro5_sd_reset_data,
        },
        {
-               .compatible = "socionext,uniphier-pxs2-mio-reset",
-               .data = uniphier_pro5_mio_reset_data,
+               .compatible = "socionext,uniphier-pxs2-sd-reset",
+               .data = uniphier_pro5_sd_reset_data,
        },
        {
                .compatible = "socionext,uniphier-ld11-mio-reset",
                .data = uniphier_sld3_mio_reset_data,
        },
        {
-               .compatible = "socionext,uniphier-ld20-mio-reset",
-               .data = uniphier_pro5_mio_reset_data,
+               .compatible = "socionext,uniphier-ld20-sd-reset",
+               .data = uniphier_pro5_sd_reset_data,
        },
        /* Peripheral reset */
        {
index 18a93d3e3f9317286c99f9718ea1d42ea95ebd50..d36534965635ca48292fd6d570bbe3a60bde75df 100644 (file)
@@ -327,6 +327,7 @@ static const struct of_device_id asm9260_dt_ids[] = {
        { .compatible = "alphascale,asm9260-rtc", },
        {}
 };
+MODULE_DEVICE_TABLE(of, asm9260_dt_ids);
 
 static struct platform_driver asm9260_rtc_driver = {
        .probe          = asm9260_rtc_probe,
index dd3d59806ffa02ef955660390533881d9f6cee62..7030d7cd38610f47e9e4bbecc0394068fcfd18da 100644 (file)
@@ -776,7 +776,7 @@ static void cmos_do_shutdown(int rtc_irq)
        spin_unlock_irq(&rtc_lock);
 }
 
-static void __exit cmos_do_remove(struct device *dev)
+static void cmos_do_remove(struct device *dev)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
        struct resource *ports;
@@ -996,8 +996,9 @@ static u32 rtc_handler(void *context)
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
        unsigned char rtc_control = 0;
        unsigned char rtc_intr;
+       unsigned long flags;
 
-       spin_lock_irq(&rtc_lock);
+       spin_lock_irqsave(&rtc_lock, flags);
        if (cmos_rtc.suspend_ctrl)
                rtc_control = CMOS_READ(RTC_CONTROL);
        if (rtc_control & RTC_AIE) {
@@ -1006,7 +1007,7 @@ static u32 rtc_handler(void *context)
                rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
                rtc_update_irq(cmos->rtc, 1, rtc_intr);
        }
-       spin_unlock_irq(&rtc_lock);
+       spin_unlock_irqrestore(&rtc_lock, flags);
 
        pm_wakeup_event(dev, 0);
        acpi_clear_event(ACPI_EVENT_RTC);
@@ -1129,7 +1130,7 @@ static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
                                pnp_irq(pnp, 0));
 }
 
-static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
+static void cmos_pnp_remove(struct pnp_dev *pnp)
 {
        cmos_do_remove(&pnp->dev);
 }
@@ -1161,7 +1162,7 @@ static struct pnp_driver cmos_pnp_driver = {
        .name           = (char *) driver_name,
        .id_table       = rtc_ids,
        .probe          = cmos_pnp_probe,
-       .remove         = __exit_p(cmos_pnp_remove),
+       .remove         = cmos_pnp_remove,
        .shutdown       = cmos_pnp_shutdown,
 
        /* flag ensures resume() gets called, and stops syslog spam */
@@ -1238,7 +1239,7 @@ static int __init cmos_platform_probe(struct platform_device *pdev)
        return cmos_do_probe(&pdev->dev, resource, irq);
 }
 
-static int __exit cmos_platform_remove(struct platform_device *pdev)
+static int cmos_platform_remove(struct platform_device *pdev)
 {
        cmos_do_remove(&pdev->dev);
        return 0;
@@ -1263,7 +1264,7 @@ static void cmos_platform_shutdown(struct platform_device *pdev)
 MODULE_ALIAS("platform:rtc_cmos");
 
 static struct platform_driver cmos_platform_driver = {
-       .remove         = __exit_p(cmos_platform_remove),
+       .remove         = cmos_platform_remove,
        .shutdown       = cmos_platform_shutdown,
        .driver = {
                .name           = driver_name,
index b04ea9b5ae67348c69210d29f3f138e7d5b649e3..51e52446eacb8f4d1e32821fd9c2d6da019825f3 100644 (file)
 /* OMAP_RTC_OSC_REG bit fields: */
 #define OMAP_RTC_OSC_32KCLK_EN         BIT(6)
 #define OMAP_RTC_OSC_SEL_32KCLK_SRC    BIT(3)
+#define OMAP_RTC_OSC_OSC32K_GZ_DISABLE BIT(4)
 
 /* OMAP_RTC_IRQWAKEEN bit fields: */
 #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN        BIT(1)
@@ -146,6 +147,7 @@ struct omap_rtc {
        u8 interrupts_reg;
        bool is_pmic_controller;
        bool has_ext_clk;
+       bool is_suspending;
        const struct omap_rtc_device_type *type;
        struct pinctrl_dev *pctldev;
 };
@@ -786,8 +788,9 @@ static int omap_rtc_probe(struct platform_device *pdev)
         */
        if (rtc->has_ext_clk) {
                reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
-               rtc_write(rtc, OMAP_RTC_OSC_REG,
-                         reg | OMAP_RTC_OSC_SEL_32KCLK_SRC);
+               reg &= ~OMAP_RTC_OSC_OSC32K_GZ_DISABLE;
+               reg |= OMAP_RTC_OSC_32KCLK_EN | OMAP_RTC_OSC_SEL_32KCLK_SRC;
+               rtc_writel(rtc, OMAP_RTC_OSC_REG, reg);
        }
 
        rtc->type->lock(rtc);
@@ -898,8 +901,7 @@ static int omap_rtc_suspend(struct device *dev)
                rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
        rtc->type->lock(rtc);
 
-       /* Disable the clock/module */
-       pm_runtime_put_sync(dev);
+       rtc->is_suspending = true;
 
        return 0;
 }
@@ -908,9 +910,6 @@ static int omap_rtc_resume(struct device *dev)
 {
        struct omap_rtc *rtc = dev_get_drvdata(dev);
 
-       /* Enable the clock/module so that we can access the registers */
-       pm_runtime_get_sync(dev);
-
        rtc->type->unlock(rtc);
        if (device_may_wakeup(dev))
                disable_irq_wake(rtc->irq_alarm);
@@ -918,11 +917,34 @@ static int omap_rtc_resume(struct device *dev)
                rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg);
        rtc->type->lock(rtc);
 
+       rtc->is_suspending = false;
+
        return 0;
 }
 #endif
 
-static SIMPLE_DEV_PM_OPS(omap_rtc_pm_ops, omap_rtc_suspend, omap_rtc_resume);
+#ifdef CONFIG_PM
+static int omap_rtc_runtime_suspend(struct device *dev)
+{
+       struct omap_rtc *rtc = dev_get_drvdata(dev);
+
+       if (rtc->is_suspending && !rtc->has_ext_clk)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int omap_rtc_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops omap_rtc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(omap_rtc_suspend, omap_rtc_resume)
+       SET_RUNTIME_PM_OPS(omap_rtc_runtime_suspend,
+                          omap_rtc_runtime_resume, NULL)
+};
 
 static void omap_rtc_shutdown(struct platform_device *pdev)
 {
index 831935af738966685415b0e2996dfb0c14af54b7..a7a88476e215e7b027958adb5c162a4d2b959802 100644 (file)
@@ -1205,7 +1205,7 @@ static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm)
                                 mdc, lpm);
                        return mdc;
                }
-               fcx_max_data = mdc * FCX_MAX_DATA_FACTOR;
+               fcx_max_data = (u32)mdc * FCX_MAX_DATA_FACTOR;
                if (fcx_max_data < private->fcx_max_data) {
                        dev_warn(&device->cdev->dev,
                                 "The maximum data size for zHPF requests %u "
@@ -1675,7 +1675,7 @@ static u32 get_fcx_max_data(struct dasd_device *device)
                         " data size for zHPF requests failed\n");
                return 0;
        } else
-               return mdc * FCX_MAX_DATA_FACTOR;
+               return (u32)mdc * FCX_MAX_DATA_FACTOR;
 }
 
 /*
index 46be25c7461e07ed0cc636cf5a1e91a21768abe2..876c7e6e3a99264b169c217389f0b0a22764662d 100644 (file)
@@ -780,7 +780,7 @@ static int cfg_wait_idle(void)
 static int __init chp_init(void)
 {
        struct chp_id chpid;
-       int ret;
+       int state, ret;
 
        ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw);
        if (ret)
@@ -791,7 +791,9 @@ static int __init chp_init(void)
                return 0;
        /* Register available channel-paths. */
        chp_id_for_each(&chpid) {
-               if (chp_info_get_status(chpid) != CHP_STATUS_NOT_RECOGNIZED)
+               state = chp_info_get_status(chpid);
+               if (state == CHP_STATUS_CONFIGURED ||
+                   state == CHP_STATUS_STANDBY)
                        chp_new(chpid);
        }
 
index 637cf8973c9e1c55d87577815c782d6409b60b5b..581001989937ce1e0aaab11c26136d5e11b4fa4d 100644 (file)
@@ -384,7 +384,7 @@ void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf,
        /* if (len > rec_len):
         * dump data up to cap_len ignoring small duplicate in rec->payload
         */
-       spin_lock_irqsave(&dbf->pay_lock, flags);
+       spin_lock(&dbf->pay_lock);
        memset(payload, 0, sizeof(*payload));
        memcpy(payload->area, paytag, ZFCP_DBF_TAG_LEN);
        payload->fsf_req_id = req_id;
index db2739079cbb4bcf2817ab450b7236a3df5922bc..790babc5ef660334c86ecb096e405a15d50bceee 100644 (file)
@@ -353,7 +353,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
 #endif
 
 
-static int probe_irq __initdata;
+static int probe_irq;
 
 /**
  * probe_intr  -       helper for IRQ autoprobe
@@ -365,7 +365,7 @@ static int probe_irq __initdata;
  * used by the IRQ probe code.
  */
 
-static irqreturn_t __init probe_intr(int irq, void *dev_id)
+static irqreturn_t probe_intr(int irq, void *dev_id)
 {
        probe_irq = irq;
        return IRQ_HANDLED;
@@ -380,7 +380,7 @@ static irqreturn_t __init probe_intr(int irq, void *dev_id)
  * and then looking to see what interrupt actually turned up.
  */
 
-static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
+static int __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
                                                int possible)
 {
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
index 3d53d636b17b8892f080855baf081299c3a349d6..f0cfb04517570839b968b0271b6029e07a3e4897 100644 (file)
@@ -2636,18 +2636,9 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
        struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
        struct CommandControlBlock *ccb;
        int target = cmd->device->id;
-       int lun = cmd->device->lun;
-       uint8_t scsicmd = cmd->cmnd[0];
        cmd->scsi_done = done;
        cmd->host_scribble = NULL;
        cmd->result = 0;
-       if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){
-               if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
-                       cmd->result = (DID_NO_CONNECT << 16);
-               }
-               cmd->scsi_done(cmd);
-               return 0;
-       }
        if (target == 16) {
                /* virtual device for iop message transfer */
                arcmsr_handle_virtual_command(acb, cmd);
index 68138a647dfc192c93f44c0ca801066a751217bb..d9239c2d49b117175d34379716b464c7b06dcfaa 100644 (file)
@@ -900,8 +900,9 @@ void hwi_ring_cq_db(struct beiscsi_hba *phba,
 static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
 {
        struct sgl_handle *psgl_handle;
+       unsigned long flags;
 
-       spin_lock_bh(&phba->io_sgl_lock);
+       spin_lock_irqsave(&phba->io_sgl_lock, flags);
        if (phba->io_sgl_hndl_avbl) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO,
                            "BM_%d : In alloc_io_sgl_handle,"
@@ -919,14 +920,16 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
                        phba->io_sgl_alloc_index++;
        } else
                psgl_handle = NULL;
-       spin_unlock_bh(&phba->io_sgl_lock);
+       spin_unlock_irqrestore(&phba->io_sgl_lock, flags);
        return psgl_handle;
 }
 
 static void
 free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
 {
-       spin_lock_bh(&phba->io_sgl_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&phba->io_sgl_lock, flags);
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO,
                    "BM_%d : In free_,io_sgl_free_index=%d\n",
                    phba->io_sgl_free_index);
@@ -941,7 +944,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
                             "value there=%p\n", phba->io_sgl_free_index,
                             phba->io_sgl_hndl_base
                             [phba->io_sgl_free_index]);
-                spin_unlock_bh(&phba->io_sgl_lock);
+                spin_unlock_irqrestore(&phba->io_sgl_lock, flags);
                return;
        }
        phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle;
@@ -950,7 +953,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
                phba->io_sgl_free_index = 0;
        else
                phba->io_sgl_free_index++;
-       spin_unlock_bh(&phba->io_sgl_lock);
+       spin_unlock_irqrestore(&phba->io_sgl_lock, flags);
 }
 
 static inline struct wrb_handle *
@@ -958,15 +961,16 @@ beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context,
                       unsigned int wrbs_per_cxn)
 {
        struct wrb_handle *pwrb_handle;
+       unsigned long flags;
 
-       spin_lock_bh(&pwrb_context->wrb_lock);
+       spin_lock_irqsave(&pwrb_context->wrb_lock, flags);
        pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index];
        pwrb_context->wrb_handles_available--;
        if (pwrb_context->alloc_index == (wrbs_per_cxn - 1))
                pwrb_context->alloc_index = 0;
        else
                pwrb_context->alloc_index++;
-       spin_unlock_bh(&pwrb_context->wrb_lock);
+       spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags);
 
        if (pwrb_handle)
                memset(pwrb_handle->pwrb, 0, sizeof(*pwrb_handle->pwrb));
@@ -1001,14 +1005,16 @@ beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context,
                       struct wrb_handle *pwrb_handle,
                       unsigned int wrbs_per_cxn)
 {
-       spin_lock_bh(&pwrb_context->wrb_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pwrb_context->wrb_lock, flags);
        pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
        pwrb_context->wrb_handles_available++;
        if (pwrb_context->free_index == (wrbs_per_cxn - 1))
                pwrb_context->free_index = 0;
        else
                pwrb_context->free_index++;
-       spin_unlock_bh(&pwrb_context->wrb_lock);
+       spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags);
 }
 
 /**
@@ -1037,8 +1043,9 @@ free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
 static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
 {
        struct sgl_handle *psgl_handle;
+       unsigned long flags;
 
-       spin_lock_bh(&phba->mgmt_sgl_lock);
+       spin_lock_irqsave(&phba->mgmt_sgl_lock, flags);
        if (phba->eh_sgl_hndl_avbl) {
                psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index];
                phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL;
@@ -1056,14 +1063,16 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
                        phba->eh_sgl_alloc_index++;
        } else
                psgl_handle = NULL;
-       spin_unlock_bh(&phba->mgmt_sgl_lock);
+       spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags);
        return psgl_handle;
 }
 
 void
 free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
 {
-       spin_lock_bh(&phba->mgmt_sgl_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&phba->mgmt_sgl_lock, flags);
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                    "BM_%d : In  free_mgmt_sgl_handle,"
                    "eh_sgl_free_index=%d\n",
@@ -1078,7 +1087,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
                            "BM_%d : Double Free in eh SGL ,"
                            "eh_sgl_free_index=%d\n",
                            phba->eh_sgl_free_index);
-               spin_unlock_bh(&phba->mgmt_sgl_lock);
+               spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags);
                return;
        }
        phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle;
@@ -1088,7 +1097,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
                phba->eh_sgl_free_index = 0;
        else
                phba->eh_sgl_free_index++;
-       spin_unlock_bh(&phba->mgmt_sgl_lock);
+       spin_unlock_irqrestore(&phba->mgmt_sgl_lock, flags);
 }
 
 static void
index aebc4ddb3060ee177c06ec9f11b62a021c346f10..ac05317bba7f3342d016e581b91ae6feffa18eff 100644 (file)
@@ -1083,7 +1083,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba)
        nonemb_cmd = &phba->boot_struct.nonemb_cmd;
        nonemb_cmd->size = sizeof(*resp);
        nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev,
-                                             sizeof(nonemb_cmd->size),
+                                             nonemb_cmd->size,
                                              &nonemb_cmd->dma);
        if (!nonemb_cmd->va) {
                mutex_unlock(&ctrl->mbox_lock);
index d1421139e6eac615d1e3ae2a9af1e02ee78d0822..2ffe029ff2b6ff29fbaaada58d277d89d2643f31 100644 (file)
@@ -2081,9 +2081,10 @@ void cxgbi_cleanup_task(struct iscsi_task *task)
        /*  never reached the xmit task callout */
        if (tdata->skb)
                __kfree_skb(tdata->skb);
-       memset(tdata, 0, sizeof(*tdata));
 
        task_release_itt(task, task->hdr_itt);
+       memset(tdata, 0, sizeof(*tdata));
+
        iscsi_tcp_cleanup_task(task);
 }
 EXPORT_SYMBOL_GPL(cxgbi_cleanup_task);
index 241829e596680f8be89941fc43ce0db642e29b18..7bb20684e9fabc3b8b950f45aee0a94d1c4e1589 100644 (file)
@@ -793,6 +793,7 @@ static void alua_rtpg_work(struct work_struct *work)
                WARN_ON(pg->flags & ALUA_PG_RUN_RTPG);
                WARN_ON(pg->flags & ALUA_PG_RUN_STPG);
                spin_unlock_irqrestore(&pg->lock, flags);
+               kref_put(&pg->kref, release_port_group);
                return;
        }
        if (pg->flags & ALUA_SYNC_STPG)
@@ -890,6 +891,7 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
                /* Do not queue if the worker is already running */
                if (!(pg->flags & ALUA_PG_RUNNING)) {
                        kref_get(&pg->kref);
+                       sdev = NULL;
                        start_queue = 1;
                }
        }
@@ -901,7 +903,8 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
        if (start_queue &&
            !queue_delayed_work(alua_wq, &pg->rtpg_work,
                                msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) {
-               scsi_device_put(sdev);
+               if (sdev)
+                       scsi_device_put(sdev);
                kref_put(&pg->kref, release_port_group);
        }
 }
index d007ec18179af9789a12e6ca7c9f5878374dc593..a1d6ab76a51418f9a4f26ecbb76529ea1b775835 100644 (file)
@@ -2009,7 +2009,7 @@ static struct hpsa_scsi_dev_t *lookup_hpsa_scsi_dev(struct ctlr_info *h,
 
 static int hpsa_slave_alloc(struct scsi_device *sdev)
 {
-       struct hpsa_scsi_dev_t *sd;
+       struct hpsa_scsi_dev_t *sd = NULL;
        unsigned long flags;
        struct ctlr_info *h;
 
@@ -2026,7 +2026,8 @@ static int hpsa_slave_alloc(struct scsi_device *sdev)
                        sd->target = sdev_id(sdev);
                        sd->lun = sdev->lun;
                }
-       } else
+       }
+       if (!sd)
                sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
                                        sdev_id(sdev), sdev->lun);
 
@@ -3840,6 +3841,7 @@ static int hpsa_update_device_info(struct ctlr_info *h,
                sizeof(this_device->vendor));
        memcpy(this_device->model, &inq_buff[16],
                sizeof(this_device->model));
+       this_device->rev = inq_buff[2];
        memset(this_device->device_id, 0,
                sizeof(this_device->device_id));
        if (hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
@@ -3929,10 +3931,14 @@ static void figure_bus_target_lun(struct ctlr_info *h,
 
        if (!is_logical_dev_addr_mode(lunaddrbytes)) {
                /* physical device, target and lun filled in later */
-               if (is_hba_lunid(lunaddrbytes))
+               if (is_hba_lunid(lunaddrbytes)) {
+                       int bus = HPSA_HBA_BUS;
+
+                       if (!device->rev)
+                               bus = HPSA_LEGACY_HBA_BUS;
                        hpsa_set_bus_target_lun(device,
-                                       HPSA_HBA_BUS, 0, lunid & 0x3fff);
-               else
+                                       bus, 0, lunid & 0x3fff);
+               else
                        /* defer target, lun assignment for physical devices */
                        hpsa_set_bus_target_lun(device,
                                        HPSA_PHYSICAL_DEVICE_BUS, -1, -1);
index 82cdfad874f3aa363d4989837d2b9455c8e0acdb..9ea162de80dcfa976b737cf209c4570de6003888 100644 (file)
@@ -69,6 +69,7 @@ struct hpsa_scsi_dev_t {
        u64 sas_address;
        unsigned char vendor[8];        /* bytes 8-15 of inquiry data */
        unsigned char model[16];        /* bytes 16-31 of inquiry data */
+       unsigned char rev;              /* byte 2 of inquiry data */
        unsigned char raid_level;       /* from inquiry page 0xC1 */
        unsigned char volume_offline;   /* discovered via TUR or VPD */
        u16 queue_depth;                /* max queue_depth for this device */
@@ -402,6 +403,7 @@ struct offline_device_entry {
 #define HPSA_RAID_VOLUME_BUS           1
 #define HPSA_EXTERNAL_RAID_VOLUME_BUS  2
 #define HPSA_HBA_BUS                   0
+#define HPSA_LEGACY_HBA_BUS            3
 
 /*
        Send the command to the hardware
index a8762a3efeef3f6e9288646b835ddf868c0013e8..532474109624d9cd9c6a52c040a1027120819886 100644 (file)
@@ -2586,7 +2586,6 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
        struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
        u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
        u32 fd_ioasc;
-       char *envp[] = { "ASYNC_ERR_LOG=1", NULL };
 
        if (ioa_cfg->sis64)
                fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
@@ -2607,8 +2606,8 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
        }
 
        list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_report_q);
+       schedule_work(&ioa_cfg->work_q);
        hostrcb = ipr_get_free_hostrcb(ioa_cfg);
-       kobject_uevent_env(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE, envp);
 
        ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
 }
index 04ce7cfb6d1b6272d26ce138a9b11ee952a20d6f..50c71678a156e8f32d833575de49379e5cd3a151 100644 (file)
@@ -308,7 +308,7 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
        fc_stats = &lport->host_stats;
        memset(fc_stats, 0, sizeof(struct fc_host_statistics));
 
-       fc_stats->seconds_since_last_reset = (lport->boot_time - jiffies) / HZ;
+       fc_stats->seconds_since_last_reset = (jiffies - lport->boot_time) / HZ;
 
        for_each_possible_cpu(cpu) {
                struct fc_stats *stats;
index c051694bfcb0f42e1e983f409a581f1da5b344d2..f9b6fba689ffb41c6806cdabeb80debe38e25189 100644 (file)
@@ -791,9 +791,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
 free_task:
        /* regular RX path uses back_lock */
-       spin_lock_bh(&session->back_lock);
+       spin_lock(&session->back_lock);
        __iscsi_put_task(task);
-       spin_unlock_bh(&session->back_lock);
+       spin_unlock(&session->back_lock);
        return NULL;
 }
 
index c5326055beee15bd9937f02c09e9f74aeec1fe6e..f4f77c5b0c83da0520eb868b79095f836179cecf 100644 (file)
@@ -1323,18 +1323,20 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 {
        lockdep_assert_held(&phba->hbalock);
 
-       BUG_ON(!piocb || !piocb->vport);
+       BUG_ON(!piocb);
 
        list_add_tail(&piocb->list, &pring->txcmplq);
        piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
 
        if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
           (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
-          (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN) &&
-           (!(piocb->vport->load_flag & FC_UNLOADING)))
-               mod_timer(&piocb->vport->els_tmofunc,
-                         jiffies +
-                         msecs_to_jiffies(1000 * (phba->fc_ratov << 1)));
+          (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
+               BUG_ON(!piocb->vport);
+               if (!(piocb->vport->load_flag & FC_UNLOADING))
+                       mod_timer(&piocb->vport->els_tmofunc,
+                                 jiffies +
+                                 msecs_to_jiffies(1000 * (phba->fc_ratov << 1)));
+       }
 
        return 0;
 }
index ca86c885dfaab4f0fb6ae3595922d6f1a77974be..3aaea713bf3712b2ad8874aaecf8a6337b7a2119 100644 (file)
@@ -2233,7 +2233,7 @@ struct megasas_instance_template {
 };
 
 #define MEGASAS_IS_LOGICAL(scp)                                                \
-       (scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
+       ((scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
 
 #define MEGASAS_DEV_INDEX(scp)                                         \
        (((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +   \
index 9ff57dee72d7b0ac20fd01e00283416864aa7cc1..d8b1fbd4c8aafc61e5e5491d5394440651a43a04 100644 (file)
@@ -1700,16 +1700,13 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
                goto out_done;
        }
 
-       switch (scmd->cmnd[0]) {
-       case SYNCHRONIZE_CACHE:
-               /*
-                * FW takes care of flush cache on its own
-                * No need to send it down
-                */
+       /*
+        * FW takes care of flush cache on its own for Virtual Disk.
+        * No need to send it down for VD. For JBOD send SYNCHRONIZE_CACHE to FW.
+        */
+       if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) && MEGASAS_IS_LOGICAL(scmd)) {
                scmd->result = DID_OK << 16;
                goto out_done;
-       default:
-               break;
        }
 
        return instance->instancet->build_and_issue_cmd(instance, scmd);
index 209a969a979d8768fa5d0dc15bc5f921f2c4ec1c..1c4744e78173bc0f78383b8f6cf901715b946d34 100644 (file)
@@ -1273,9 +1273,9 @@ scsih_target_alloc(struct scsi_target *starget)
                        sas_target_priv_data->handle = raid_device->handle;
                        sas_target_priv_data->sas_address = raid_device->wwid;
                        sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
-                       sas_target_priv_data->raid_device = raid_device;
                        if (ioc->is_warpdrive)
-                               raid_device->starget = starget;
+                               sas_target_priv_data->raid_device = raid_device;
+                       raid_device->starget = starget;
                }
                spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
                return 0;
@@ -3885,6 +3885,11 @@ _scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
        }
 }
 
+static inline bool ata_12_16_cmd(struct scsi_cmnd *scmd)
+{
+       return (scmd->cmnd[0] == ATA_12 || scmd->cmnd[0] == ATA_16);
+}
+
 /**
  * _scsih_flush_running_cmds - completing outstanding commands.
  * @ioc: per adapter object
@@ -3906,6 +3911,9 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc)
                if (!scmd)
                        continue;
                count++;
+               if (ata_12_16_cmd(scmd))
+                       scsi_internal_device_unblock(scmd->device,
+                                                       SDEV_RUNNING);
                mpt3sas_base_free_smid(ioc, smid);
                scsi_dma_unmap(scmd);
                if (ioc->pci_error_recovery)
@@ -4010,8 +4018,6 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
            SAM_STAT_CHECK_CONDITION;
 }
 
-
-
 /**
  * scsih_qcmd - main scsi request entry point
  * @scmd: pointer to scsi command object
@@ -4038,6 +4044,13 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
        if (ioc->logging_level & MPT_DEBUG_SCSI)
                scsi_print_command(scmd);
 
+       /*
+        * Lock the device for any subsequent command until command is
+        * done.
+        */
+       if (ata_12_16_cmd(scmd))
+               scsi_internal_device_block(scmd->device);
+
        sas_device_priv_data = scmd->device->hostdata;
        if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
                scmd->result = DID_NO_CONNECT << 16;
@@ -4613,6 +4626,9 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        if (scmd == NULL)
                return 1;
 
+       if (ata_12_16_cmd(scmd))
+               scsi_internal_device_unblock(scmd->device, SDEV_RUNNING);
+
        mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
 
        if (mpi_reply == NULL) {
index 86eb19902bacef9f62e808833cbe86387b1d1771..c7cc8035eacb371eb3ae6e038abb6df7c94e7169 100644 (file)
@@ -791,8 +791,10 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
        slot->slot_tag = tag;
 
        slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma);
-       if (!slot->buf)
+       if (!slot->buf) {
+               rc = -ENOMEM;
                goto err_out_tag;
+       }
        memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
 
        tei.task = task;
index ace65db1d2a25becd6dc3c4a158d932f7dab8fff..56d6142852a553ed9ad8011cb4c18a84e8656e0d 100644 (file)
@@ -707,6 +707,11 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        srb_t *sp;
        int rval;
 
+       if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) {
+               cmd->result = DID_NO_CONNECT << 16;
+               goto qc24_fail_command;
+       }
+
        if (ha->flags.eeh_busy) {
                if (ha->flags.pci_channel_io_perm_failure) {
                        ql_dbg(ql_dbg_aer, vha, 0x9010,
@@ -1451,6 +1456,20 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
                for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
                        sp = req->outstanding_cmds[cnt];
                        if (sp) {
+                               /* Don't abort commands in adapter during EEH
+                                * recovery as it's not accessible/responding.
+                                */
+                               if (!ha->flags.eeh_busy) {
+                                       /* Get a reference to the sp and drop the lock.
+                                        * The reference ensures this sp->done() call
+                                        * - and not the call in qla2xxx_eh_abort() -
+                                        * ends the SCSI command (with result 'res').
+                                        */
+                                       sp_get(sp);
+                                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+                                       qla2xxx_eh_abort(GET_CMD_SP(sp));
+                                       spin_lock_irqsave(&ha->hardware_lock, flags);
+                               }
                                req->outstanding_cmds[cnt] = NULL;
                                sp->done(vha, sp, res);
                        }
@@ -2341,6 +2360,8 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
        scsi_qla_host_t *vha = shost_priv(shost);
 
+       if (test_bit(UNLOADING, &vha->dpc_flags))
+               return 1;
        if (!vha->host)
                return 1;
        if (time > vha->hw->loop_reset_delay * HZ)
index 4377e87ee79c360c4bb797b4a93df405b02c1f00..892a0b058b997e2ffad02d913347aee0d4c9f542 100644 (file)
@@ -356,8 +356,8 @@ struct qlogicpti {
 
        /* The rest of the elements are unimportant for performance. */
        struct qlogicpti         *next;
-       __u32                     res_dvma;             /* Ptr to RESPONSE bufs (DVMA)*/
-       __u32                     req_dvma;             /* Ptr to REQUEST bufs (DVMA) */
+       dma_addr_t                res_dvma;             /* Ptr to RESPONSE bufs (DVMA)*/
+       dma_addr_t                req_dvma;             /* Ptr to REQUEST bufs (DVMA) */
        u_char                    fware_majrev, fware_minrev, fware_micrev;
        struct Scsi_Host         *qhost;
        int                       qpti_id;
index c905709707f0a2178ca82823fb2be8523e3abe96..cf04a364fd8b35f869c31e44491d237ae1b3bc6e 100644 (file)
@@ -5134,6 +5134,7 @@ static void __exit scsi_debug_exit(void)
        bus_unregister(&pseudo_lld_bus);
        root_device_unregister(pseudo_primary);
 
+       vfree(map_storep);
        vfree(dif_storep);
        vfree(fake_storep);
        kfree(sdebug_q_arr);
index 54d446c9f56e0e77372f9fe67be14d04a96a3d53..b8d3b97b217ac552ed6166e4ebe2a1c1483e5ca2 100644 (file)
@@ -36,9 +36,9 @@ struct scsi_dh_blist {
 };
 
 static const struct scsi_dh_blist scsi_dh_blist[] = {
-       {"DGC", "RAID",                 "clariion" },
-       {"DGC", "DISK",                 "clariion" },
-       {"DGC", "VRAID",                "clariion" },
+       {"DGC", "RAID",                 "emc" },
+       {"DGC", "DISK",                 "emc" },
+       {"DGC", "VRAID",                "emc" },
 
        {"COMPAQ", "MSA1000 VOLUME",    "hp_sw" },
        {"COMPAQ", "HSV110",            "hp_sw" },
index 212e98d940bc222885d8ece9a675df4782cc8be1..6f7128f49c30d62d381556275d667c84eda6ab62 100644 (file)
@@ -1307,7 +1307,6 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
 static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
                                enum scsi_scan_mode rescan)
 {
-       char devname[64];
        unsigned char scsi_cmd[MAX_COMMAND_SIZE];
        unsigned int length;
        u64 lun;
@@ -1349,9 +1348,6 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
                }
        }
 
-       sprintf(devname, "host %d channel %d id %d",
-               shost->host_no, sdev->channel, sdev->id);
-
        /*
         * Allocate enough to hold the header (the same size as one scsi_lun)
         * plus the number of luns we are requesting.  511 was the default
@@ -1470,12 +1466,12 @@ retry:
  out_err:
        kfree(lun_data);
  out:
-       scsi_device_put(sdev);
        if (scsi_device_created(sdev))
                /*
                 * the sdev we used didn't appear in the report luns scan
                 */
                __scsi_remove_device(sdev);
+       scsi_device_put(sdev);
        return ret;
 }
 
index 7af5226aa55ba0937b69b8b0f2d5d070f3eccf7d..618422ea3a4123d8d0b115f8811634e8225de8a1 100644 (file)
@@ -4922,9 +4922,8 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
        res = get_user_pages_unlocked(
                uaddr,
                nr_pages,
-               rw == READ,
-               0, /* don't force */
-               pages);
+               pages,
+               rw == READ ? FOLL_WRITE : 0); /* don't force */
 
        /* Errors and no page mapped should return here */
        if (res < nr_pages)
index 4a0d3cdc607cd5d8bfdb28867187fd7d12df0919..15ca09cd16f34ad6f7a8ece088e1dababef3a1b5 100644 (file)
@@ -793,6 +793,7 @@ static int pvscsi_abort(struct scsi_cmnd *cmd)
        unsigned long flags;
        int result = SUCCESS;
        DECLARE_COMPLETION_ONSTACK(abort_cmp);
+       int done;
 
        scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n",
                    adapter->host->host_no, cmd);
@@ -824,10 +825,10 @@ static int pvscsi_abort(struct scsi_cmnd *cmd)
        pvscsi_abort_cmd(adapter, ctx);
        spin_unlock_irqrestore(&adapter->hw_lock, flags);
        /* Wait for 2 secs for the completion. */
-       wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000));
+       done = wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000));
        spin_lock_irqsave(&adapter->hw_lock, flags);
 
-       if (!completion_done(&abort_cmp)) {
+       if (!done) {
                /*
                 * Failed to abort the command, unmark the fact that it
                 * was requested to be aborted.
index c097d2ccbde3163eaa9d1ab0a20f402446c79002..d41292ef85f2ff93b879237a8da7f2357c489b24 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/types.h>
 
-#define PVSCSI_DRIVER_VERSION_STRING   "1.0.6.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING   "1.0.7.0-k"
 
 #define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
 
index 35c0dd94566814c484758bae43d354bf4e282e13..a67b0ff6a362380e4f62382c12c557f98a127947 100644 (file)
@@ -70,6 +70,7 @@
 #define SPI_SR                 0x2c
 #define SPI_SR_EOQF            0x10000000
 #define SPI_SR_TCFQF           0x80000000
+#define SPI_SR_CLEAR           0xdaad0000
 
 #define SPI_RSER               0x30
 #define SPI_RSER_EOQFE         0x10000000
@@ -646,6 +647,11 @@ static const struct regmap_config dspi_regmap_config = {
        .max_register = 0x88,
 };
 
+static void dspi_init(struct fsl_dspi *dspi)
+{
+       regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
+}
+
 static int dspi_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -709,6 +715,7 @@ static int dspi_probe(struct platform_device *pdev)
                return PTR_ERR(dspi->regmap);
        }
 
+       dspi_init(dspi);
        dspi->irq = platform_get_irq(pdev, 0);
        if (dspi->irq < 0) {
                dev_err(&pdev->dev, "can't get platform irq\n");
index 7451585a080e5ccc13e2fc59d532c70e786a4ce0..2c175b9495f7ee102a0d70a96f42fa730c019247 100644 (file)
@@ -458,7 +458,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
 
                mspi->len -= rx_nr_bytes;
 
-               if (mspi->rx)
+               if (rx_nr_bytes && mspi->rx)
                        mspi->get_rx(rx_data, mspi);
        }
 
index 5787b723b593f79bb5e55f3b68abcb2f19d4b5cb..838783c3fed0ae81626099b8e295dc12963a1360 100644 (file)
@@ -1618,9 +1618,11 @@ static void of_register_spi_devices(struct spi_master *master)
                if (of_node_test_and_set_flag(nc, OF_POPULATED))
                        continue;
                spi = of_register_spi_device(master, nc);
-               if (IS_ERR(spi))
+               if (IS_ERR(spi)) {
                        dev_warn(&master->dev, "Failed to create SPI device for %s\n",
                                nc->full_name);
+                       of_node_clear_flag(nc, OF_POPULATED);
+               }
        }
 }
 #else
@@ -3131,6 +3133,7 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,
                if (IS_ERR(spi)) {
                        pr_err("%s: failed to create for '%s'\n",
                                        __func__, rd->dn->full_name);
+                       of_node_clear_flag(rd->dn, OF_POPULATED);
                        return notifier_from_errno(PTR_ERR(spi));
                }
                break;
index 396ded52ab70242b8b3c069c52cc7fed2c44624d..209a8f7ef02bd4b04cabefad50d17351e5e6990c 100644 (file)
@@ -1187,8 +1187,10 @@ int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query)
                hdata.type = heap->type;
                hdata.heap_id = heap->id;
 
-               ret = copy_to_user(&buffer[cnt],
-                                  &hdata, sizeof(hdata));
+               if (copy_to_user(&buffer[cnt], &hdata, sizeof(hdata))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
 
                cnt++;
                if (cnt >= max_cnt)
index 15bac92b7f042023dbe327de670d8cd011a7f323..46b2bb99bfd6b2081a0775ce9ad87393bfcd5b2e 100644 (file)
@@ -107,7 +107,7 @@ struct ion_platform_data *ion_parse_dt(struct platform_device *pdev,
 
                heap_pdev = of_platform_device_create(node, heaps[i].name,
                                                      &pdev->dev);
-               if (!pdev)
+               if (!heap_pdev)
                        return ERR_PTR(-ENOMEM);
                heap_pdev->dev.platform_data = &heaps[i];
 
index 7043eb0543f6b15c98161e341b354a05e7748e02..5ab49a798164bfb8c400609ed4f36fa2c0126cc6 100644 (file)
@@ -207,7 +207,8 @@ static int ni_tio_clock_period_ps(const struct ni_gpct *counter,
                 * clock period is specified by user with prescaling
                 * already taken into account.
                 */
-               return counter->clock_period_ps;
+               *period_ps = counter->clock_period_ps;
+               return 0;
        }
 
        switch (generic_clock_source & NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK) {
index e36ee984485bfcf3aea56f777e9f7ec4c671ed02..d33d6fe078ad730ae3cdb4c7d9291c23d3711397 100644 (file)
@@ -128,6 +128,7 @@ int arche_platform_change_state(enum arche_platform_state state,
        pdev = of_find_device_by_node(np);
        if (!pdev) {
                pr_err("arche-platform device not found\n");
+               of_node_put(np);
                return -ENODEV;
        }
 
@@ -185,6 +186,7 @@ int arche_platform_change_state(enum arche_platform_state state,
 exit:
        spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
        mutex_unlock(&arche_pdata->platform_state_mutex);
+       put_device(&pdev->dev);
        of_node_put(np);
        return ret;
 }
index 071bb1cfd3ae1d38c510c19adbf7cdd3d9daa9a7..baab460eeaa3828f7a3f84490f4dda566b647c44 100644 (file)
@@ -1548,7 +1548,8 @@ static int ap_probe(struct usb_interface *interface,
        INIT_LIST_HEAD(&es2->arpcs);
        spin_lock_init(&es2->arpc_lock);
 
-       if (es2_arpc_in_enable(es2))
+       retval = es2_arpc_in_enable(es2);
+       if (retval)
                goto error;
 
        retval = gb_hd_add(hd);
index 5e06e4229e4239e3e307ce2a0faac266ddd1c7e5..250caa00de5e9f4665978ef0105a8b42c2e49420 100644 (file)
@@ -702,15 +702,13 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
        ret = gb_gpio_irqchip_add(gpio, irqc, 0,
                                   handle_level_irq, IRQ_TYPE_NONE);
        if (ret) {
-               dev_err(&connection->bundle->dev,
-                       "failed to add irq chip: %d\n", ret);
+               dev_err(&gbphy_dev->dev, "failed to add irq chip: %d\n", ret);
                goto exit_line_free;
        }
 
        ret = gpiochip_add(gpio);
        if (ret) {
-               dev_err(&connection->bundle->dev,
-                       "failed to add gpio chip: %d\n", ret);
+               dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret);
                goto exit_gpio_irqchip_remove;
        }
 
index 69f67ddbd4a364d00fe31932a15c773599eb8851..660b4674a76f584aa8a426abffc595d05051659c 100644 (file)
@@ -127,7 +127,7 @@ struct gb_module *gb_module_create(struct gb_host_device *hd, u8 module_id,
        return module;
 
 err_put_interfaces:
-       for (--i; i > 0; --i)
+       for (--i; i >= 0; --i)
                gb_interface_put(module->interfaces[i]);
 
        put_device(&module->dev);
index 5ee7954bd9f91af58091454a478b64e1a0dd7741..2633d2bfb1b4f86bfd34e0da52f1e647b105e301 100644 (file)
@@ -888,7 +888,7 @@ static int gb_uart_probe(struct gbphy_device *gbphy_dev,
        minor = alloc_minor(gb_tty);
        if (minor < 0) {
                if (minor == -ENOSPC) {
-                       dev_err(&connection->bundle->dev,
+                       dev_err(&gbphy_dev->dev,
                                "no more free minor numbers\n");
                        retval = -ENODEV;
                } else {
index d626125d7af942511853404649318da45548a662..564b36d4f6486c7c0dad7a18cca4b0bf0155c4a9 100644 (file)
@@ -468,6 +468,8 @@ static inline int __sca3000_get_base_freq(struct sca3000_state *st,
        case SCA3000_MEAS_MODE_OP_2:
                *base_freq = info->option_mode_2_freq;
                break;
+       default:
+               ret = -EINVAL;
        }
 error_ret:
        return ret;
index 5eecf1cb1028892796872ad592daf3a5e4d89e3c..3892a747041082518f3c1cbec66755b180124e24 100644 (file)
@@ -655,6 +655,7 @@ static void ad5933_work(struct work_struct *work)
        __be16 buf[2];
        int val[2];
        unsigned char status;
+       int ret;
 
        mutex_lock(&indio_dev->mlock);
        if (st->state == AD5933_CTRL_INIT_START_FREQ) {
@@ -662,19 +663,22 @@ static void ad5933_work(struct work_struct *work)
                ad5933_cmd(st, AD5933_CTRL_START_SWEEP);
                st->state = AD5933_CTRL_START_SWEEP;
                schedule_delayed_work(&st->work, st->poll_time_jiffies);
-               mutex_unlock(&indio_dev->mlock);
-               return;
+               goto out;
        }
 
-       ad5933_i2c_read(st->client, AD5933_REG_STATUS, 1, &status);
+       ret = ad5933_i2c_read(st->client, AD5933_REG_STATUS, 1, &status);
+       if (ret)
+               goto out;
 
        if (status & AD5933_STAT_DATA_VALID) {
                int scan_count = bitmap_weight(indio_dev->active_scan_mask,
                                               indio_dev->masklength);
-               ad5933_i2c_read(st->client,
+               ret = ad5933_i2c_read(st->client,
                                test_bit(1, indio_dev->active_scan_mask) ?
                                AD5933_REG_REAL_DATA : AD5933_REG_IMAG_DATA,
                                scan_count * 2, (u8 *)buf);
+               if (ret)
+                       goto out;
 
                if (scan_count == 2) {
                        val[0] = be16_to_cpu(buf[0]);
@@ -686,8 +690,7 @@ static void ad5933_work(struct work_struct *work)
        } else {
                /* no data available - try again later */
                schedule_delayed_work(&st->work, st->poll_time_jiffies);
-               mutex_unlock(&indio_dev->mlock);
-               return;
+               goto out;
        }
 
        if (status & AD5933_STAT_SWEEP_DONE) {
@@ -700,7 +703,7 @@ static void ad5933_work(struct work_struct *work)
                ad5933_cmd(st, AD5933_CTRL_INC_FREQ);
                schedule_delayed_work(&st->work, st->poll_time_jiffies);
        }
-
+out:
        mutex_unlock(&indio_dev->mlock);
 }
 
index 6eae605959055ec75def8fde36793f2678758606..23fda9d98bffd571fd0b7d3de323b6b457237e54 100644 (file)
@@ -871,12 +871,10 @@ static ssize_t xattr_cache_store(struct kobject *kobj,
 }
 LUSTRE_RW_ATTR(xattr_cache);
 
-static ssize_t unstable_stats_show(struct kobject *kobj,
-                                  struct attribute *attr,
-                                  char *buf)
+static int ll_unstable_stats_seq_show(struct seq_file *m, void *v)
 {
-       struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
-                                             ll_kobj);
+       struct super_block     *sb    = m->private;
+       struct ll_sb_info      *sbi   = ll_s2sbi(sb);
        struct cl_client_cache *cache = sbi->ll_cache;
        long pages;
        int mb;
@@ -884,19 +882,21 @@ static ssize_t unstable_stats_show(struct kobject *kobj,
        pages = atomic_long_read(&cache->ccc_unstable_nr);
        mb = (pages * PAGE_SIZE) >> 20;
 
-       return sprintf(buf, "unstable_check:     %8d\n"
-                           "unstable_pages: %12ld\n"
-                           "unstable_mb:        %8d\n",
-                           cache->ccc_unstable_check, pages, mb);
+       seq_printf(m,
+                  "unstable_check:     %8d\n"
+                  "unstable_pages: %12ld\n"
+                  "unstable_mb:        %8d\n",
+                  cache->ccc_unstable_check, pages, mb);
+
+       return 0;
 }
 
-static ssize_t unstable_stats_store(struct kobject *kobj,
-                                   struct attribute *attr,
-                                   const char *buffer,
-                                   size_t count)
+static ssize_t ll_unstable_stats_seq_write(struct file *file,
+                                          const char __user *buffer,
+                                          size_t count, loff_t *off)
 {
-       struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
-                                             ll_kobj);
+       struct super_block *sb = ((struct seq_file *)file->private_data)->private;
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
        char kernbuf[128];
        int val, rc;
 
@@ -922,7 +922,7 @@ static ssize_t unstable_stats_store(struct kobject *kobj,
 
        return count;
 }
-LUSTRE_RW_ATTR(unstable_stats);
+LPROC_SEQ_FOPS(ll_unstable_stats);
 
 static ssize_t root_squash_show(struct kobject *kobj, struct attribute *attr,
                                char *buf)
@@ -995,6 +995,7 @@ static struct lprocfs_vars lprocfs_llite_obd_vars[] = {
        /* { "filegroups",   lprocfs_rd_filegroups,  0, 0 }, */
        { "max_cached_mb",    &ll_max_cached_mb_fops, NULL },
        { "statahead_stats",  &ll_statahead_stats_fops, NULL, 0 },
+       { "unstable_stats",   &ll_unstable_stats_fops, NULL },
        { "sbi_flags",        &ll_sbi_flags_fops, NULL, 0 },
        { .name =               "nosquash_nids",
          .fops =               &ll_nosquash_nids_fops          },
@@ -1026,7 +1027,6 @@ static struct attribute *llite_attrs[] = {
        &lustre_attr_max_easize.attr,
        &lustre_attr_default_easize.attr,
        &lustre_attr_xattr_cache.attr,
-       &lustre_attr_unstable_stats.attr,
        &lustre_attr_root_squash.attr,
        NULL,
 };
index ea15cc6380970e159addcf91ce18c431b1cb1ef0..4d9bd02ede4700c8a89460ed68b0ce66898d3c26 100644 (file)
@@ -482,6 +482,8 @@ static int bcm2048_set_rds_no_lock(struct bcm2048_device *bdev, u8 rds_on)
                                           flags);
                memset(&bdev->rds_info, 0, sizeof(bdev->rds_info));
        }
+       if (err)
+               return err;
 
        return bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM,
                                    bdev->cache_fm_rds_system);
index a324322ee0ad1ebec13e280368538056a691fb18..499952c8ef3915ba54afe52347bc220cbad1387c 100644 (file)
@@ -106,13 +106,12 @@ static int nvec_mouse_probe(struct platform_device *pdev)
 {
        struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
        struct serio *ser_dev;
-       char mouse_reset[] = { NVEC_PS2, SEND_COMMAND, PSMOUSE_RST, 3 };
 
-       ser_dev = devm_kzalloc(&pdev->dev, sizeof(struct serio), GFP_KERNEL);
+       ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
        if (!ser_dev)
                return -ENOMEM;
 
-       ser_dev->id.type = SERIO_PS_PSTHRU;
+       ser_dev->id.type = SERIO_8042;
        ser_dev->write = ps2_sendcommand;
        ser_dev->start = ps2_startstreaming;
        ser_dev->stop = ps2_stopstreaming;
@@ -127,9 +126,6 @@ static int nvec_mouse_probe(struct platform_device *pdev)
 
        serio_register_port(ser_dev);
 
-       /* mouse reset */
-       nvec_write_async(nvec, mouse_reset, sizeof(mouse_reset));
-
        return 0;
 }
 
index 955247979aaa4d9a72575d9ed3c9f1c13995cb5a..4ed6d8d7712ae1077395f6921430d9319e3a9df2 100644 (file)
 
 #define PANEL_PLANE_TL                                0x08001C
 #define PANEL_PLANE_TL_TOP_SHIFT                      16
-#define PANEL_PLANE_TL_TOP_MASK                       (0xeff << 16)
-#define PANEL_PLANE_TL_LEFT_MASK                      0xeff
+#define PANEL_PLANE_TL_TOP_MASK                       (0x7ff << 16)
+#define PANEL_PLANE_TL_LEFT_MASK                      0x7ff
 
 #define PANEL_PLANE_BR                                0x080020
 #define PANEL_PLANE_BR_BOTTOM_SHIFT                   16
-#define PANEL_PLANE_BR_BOTTOM_MASK                    (0xeff << 16)
-#define PANEL_PLANE_BR_RIGHT_MASK                     0xeff
+#define PANEL_PLANE_BR_BOTTOM_MASK                    (0x7ff << 16)
+#define PANEL_PLANE_BR_RIGHT_MASK                     0x7ff
 
 #define PANEL_HORIZONTAL_TOTAL                        0x080024
 #define PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT            16
index c29040fdf9a7757b7c0d428616e244a6e4d5f697..1091b9f1dd070e3d27c269402b43b0a09d96bcdc 100644 (file)
@@ -423,8 +423,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
                actual_pages = get_user_pages(task, task->mm,
                                          (unsigned long)buf & ~(PAGE_SIZE - 1),
                                          num_pages,
-                                         (type == PAGELIST_READ) /*Write */ ,
-                                         0 /*Force */ ,
+                                         (type == PAGELIST_READ) ? FOLL_WRITE : 0,
                                          pages,
                                          NULL /*vmas */);
                up_read(&task->mm->mmap_sem);
index e11c0e07471bc7ebba04e48d3efc746236ec2f4e..7b6cd4d80621e38ff6d47fcd87b45fbe9cd4259b 100644 (file)
@@ -1477,8 +1477,7 @@ dump_phys_mem(void *virt_addr, uint32_t num_bytes)
                current->mm,              /* mm */
                (unsigned long)virt_addr, /* start */
                num_pages,                /* len */
-               0,                        /* write */
-               0,                        /* force */
+               0,                        /* gup_flags */
                pages,                    /* pages (array of page pointers) */
                NULL);                    /* vmas */
        up_read(&current->mm->mmap_sem);
index 78f5613e9467cf5579a57f6d13137af9f5e1d5b9..6ab7443eabdefa2bdf7c4a4653433e10250b9bf2 100644 (file)
@@ -3388,7 +3388,6 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
 
        clients_count++;
 
-       destroy_workqueue(hif_workqueue);
 _fail_:
        return result;
 }
index 39b928c2849d71c47390ef55002dc767f7ae4e12..b7d747e92c7abf589e35154b25482a9dedb57118 100644 (file)
@@ -1804,6 +1804,10 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * Otherwise, initiator is not expecting a NOPIN is response.
         * Just ignore for now.
         */
+
+       if (cmd)
+               iscsit_free_cmd(cmd, false);
+
         return 0;
 }
 EXPORT_SYMBOL(iscsit_process_nop_out);
@@ -2982,7 +2986,7 @@ iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
 
        pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x,"
                " StatSN: 0x%08x, Length %u\n", (nopout_response) ?
-               "Solicitied" : "Unsolicitied", cmd->init_task_tag,
+               "Solicited" : "Unsolicited", cmd->init_task_tag,
                cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
 }
 EXPORT_SYMBOL(iscsit_build_nopin_rsp);
index adf419fa429189ceca94d04782221fc34de23b6c..15f79a2ca34ab6e17fd5fda6f68425b9af1809eb 100644 (file)
@@ -434,7 +434,7 @@ static int iscsi_login_zero_tsih_s2(
 
                /*
                 * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
-                * Immediate Data + Unsolicitied Data-OUT if necessary..
+                * Immediate Data + Unsolicited Data-OUT if necessary..
                 */
                param = iscsi_find_param_from_key("MaxRecvDataSegmentLength",
                                                  conn->param_list);
@@ -646,7 +646,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
 {
        struct iscsi_session *sess = conn->sess;
        /*
-        * FIXME: Unsolicitied NopIN support for ISER
+        * FIXME: Unsolicited NopIN support for ISER
         */
        if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
                return;
index 6094a6beddde9fb5d045644b6b11b32e6bd149c1..7dfefd66df93874b1359824890b4b760275ff2c6 100644 (file)
@@ -754,15 +754,7 @@ EXPORT_SYMBOL(target_complete_cmd);
 
 void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
 {
-       if (scsi_status != SAM_STAT_GOOD) {
-               return;
-       }
-
-       /*
-        * Calculate new residual count based upon length of SCSI data
-        * transferred.
-        */
-       if (length < cmd->data_length) {
+       if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
                if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
                        cmd->residual_count += cmd->data_length - length;
                } else {
@@ -771,12 +763,6 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len
                }
 
                cmd->data_length = length;
-       } else if (length > cmd->data_length) {
-               cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
-               cmd->residual_count = length - cmd->data_length;
-       } else {
-               cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT);
-               cmd->residual_count = 0;
        }
 
        target_complete_cmd(cmd, scsi_status);
@@ -1706,6 +1692,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
        case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
        case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
        case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
+       case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
                break;
        case TCM_OUT_OF_RESOURCES:
                sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -2547,8 +2534,12 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
         * fabric acknowledgement that requires two target_put_sess_cmd()
         * invocations before se_cmd descriptor release.
         */
-       if (ack_kref)
-               kref_get(&se_cmd->cmd_kref);
+       if (ack_kref) {
+               if (!kref_get_unless_zero(&se_cmd->cmd_kref))
+                       return -EINVAL;
+
+               se_cmd->se_cmd_flags |= SCF_ACK_KREF;
+       }
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (se_sess->sess_tearing_down) {
@@ -2627,7 +2618,7 @@ EXPORT_SYMBOL(target_put_sess_cmd);
  */
 void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
 {
-       struct se_cmd *se_cmd;
+       struct se_cmd *se_cmd, *tmp_cmd;
        unsigned long flags;
        int rc;
 
@@ -2639,14 +2630,16 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
        se_sess->sess_tearing_down = 1;
        list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
 
-       list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) {
+       list_for_each_entry_safe(se_cmd, tmp_cmd,
+                                &se_sess->sess_wait_list, se_cmd_list) {
                rc = kref_get_unless_zero(&se_cmd->cmd_kref);
                if (rc) {
                        se_cmd->cmd_wait_set = 1;
                        spin_lock(&se_cmd->t_state_lock);
                        se_cmd->transport_state |= CMD_T_FABRIC_STOP;
                        spin_unlock(&se_cmd->t_state_lock);
-               }
+               } else
+                       list_del_init(&se_cmd->se_cmd_list);
        }
 
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
@@ -2871,6 +2864,12 @@ static const struct sense_info sense_info_table[] = {
                .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
                .add_sector_info = true,
        },
+       [TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = {
+               .key = COPY_ABORTED,
+               .asc = 0x0d,
+               .ascq = 0x02, /* COPY TARGET DEVICE NOT REACHABLE */
+
+       },
        [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = {
                /*
                 * Returning ILLEGAL REQUEST would cause immediate IO errors on
index 62bf4fe5704a929aa01a5f970f26e7f1020f9442..47562509b4892b07b85cb304a3190804c658d6e9 100644 (file)
@@ -96,7 +96,7 @@ struct tcmu_dev {
        size_t dev_size;
        u32 cmdr_size;
        u32 cmdr_last_cleaned;
-       /* Offset of data ring from start of mb */
+       /* Offset of data area from start of mb */
        /* Must add data_off and mb_addr to get the address */
        size_t data_off;
        size_t data_size;
@@ -349,7 +349,7 @@ static inline size_t spc_bitmap_free(unsigned long *bitmap)
 
 /*
  * We can't queue a command until we have space available on the cmd ring *and*
- * space available on the data ring.
+ * space available on the data area.
  *
  * Called with ring lock held.
  */
@@ -389,7 +389,8 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t d
        return true;
 }
 
-static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
+static sense_reason_t
+tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
 {
        struct tcmu_dev *udev = tcmu_cmd->tcmu_dev;
        struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
@@ -405,7 +406,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
        DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS);
 
        if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags))
-               return -EINVAL;
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
        /*
         * Must be a certain minimum size for response sense info, but
@@ -432,11 +433,14 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
                BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents));
                data_length += se_cmd->t_bidi_data_sg->length;
        }
-       if ((command_size > (udev->cmdr_size / 2))
-           || data_length > udev->data_size)
-               pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu "
-                       "cmd/data ring buffers\n", command_size, data_length,
+       if ((command_size > (udev->cmdr_size / 2)) ||
+           data_length > udev->data_size) {
+               pr_warn("TCMU: Request of size %zu/%zu is too big for %u/%zu "
+                       "cmd ring/data area\n", command_size, data_length,
                        udev->cmdr_size, udev->data_size);
+               spin_unlock_irq(&udev->cmdr_lock);
+               return TCM_INVALID_CDB_FIELD;
+       }
 
        while (!is_ring_space_avail(udev, command_size, data_length)) {
                int ret;
@@ -450,7 +454,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
                finish_wait(&udev->wait_cmdr, &__wait);
                if (!ret) {
                        pr_warn("tcmu: command timed out\n");
-                       return -ETIMEDOUT;
+                       return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
                }
 
                spin_lock_irq(&udev->cmdr_lock);
@@ -487,9 +491,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
 
        bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS);
 
-       /*
-        * Fix up iovecs, and handle if allocation in data ring wrapped.
-        */
+       /* Handle allocating space from the data area */
        iov = &entry->req.iov[0];
        iov_cnt = 0;
        copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE
@@ -526,10 +528,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
        mod_timer(&udev->timeout,
                round_jiffies_up(jiffies + msecs_to_jiffies(TCMU_TIME_OUT)));
 
-       return 0;
+       return TCM_NO_SENSE;
 }
 
-static int tcmu_queue_cmd(struct se_cmd *se_cmd)
+static sense_reason_t
+tcmu_queue_cmd(struct se_cmd *se_cmd)
 {
        struct se_device *se_dev = se_cmd->se_dev;
        struct tcmu_dev *udev = TCMU_DEV(se_dev);
@@ -538,10 +541,10 @@ static int tcmu_queue_cmd(struct se_cmd *se_cmd)
 
        tcmu_cmd = tcmu_alloc_cmd(se_cmd);
        if (!tcmu_cmd)
-               return -ENOMEM;
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
        ret = tcmu_queue_cmd_ring(tcmu_cmd);
-       if (ret < 0) {
+       if (ret != TCM_NO_SENSE) {
                pr_err("TCMU: Could not queue command\n");
                spin_lock_irq(&udev->commands_lock);
                idr_remove(&udev->commands, tcmu_cmd->cmd_id);
@@ -561,7 +564,7 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
        if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
                /*
                 * cmd has been completed already from timeout, just reclaim
-                * data ring space and free cmd
+                * data area space and free cmd
                 */
                free_data_area(udev, cmd);
 
@@ -1128,21 +1131,10 @@ static sector_t tcmu_get_blocks(struct se_device *dev)
                       dev->dev_attrib.block_size);
 }
 
-static sense_reason_t
-tcmu_pass_op(struct se_cmd *se_cmd)
-{
-       int 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_parse_cdb(struct se_cmd *cmd)
 {
-       return passthrough_parse_cdb(cmd, tcmu_pass_op);
+       return passthrough_parse_cdb(cmd, tcmu_queue_cmd);
 }
 
 static const struct target_backend_ops tcmu_ops = {
index 75cd85426ae3a27f276947f667794acb7c9454d0..094a1440eacb3dccdd9c35a678a2940c3e03216d 100644 (file)
@@ -104,7 +104,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
        }
        mutex_unlock(&g_device_mutex);
 
-       pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+       pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
        return -EINVAL;
 }
 
@@ -185,7 +185,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
 
 static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
                                struct xcopy_op *xop, unsigned char *p,
-                               unsigned short tdll)
+                               unsigned short tdll, sense_reason_t *sense_ret)
 {
        struct se_device *local_dev = se_cmd->se_dev;
        unsigned char *desc = p;
@@ -193,6 +193,8 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
        unsigned short start = 0;
        bool src = true;
 
+       *sense_ret = TCM_INVALID_PARAMETER_LIST;
+
        if (offset != 0) {
                pr_err("XCOPY target descriptor list length is not"
                        " multiple of %d\n", XCOPY_TARGET_DESC_LEN);
@@ -243,9 +245,16 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
                rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
        else
                rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
-
-       if (rc < 0)
+       /*
+        * If a matching IEEE NAA 0x83 descriptor for the requested device
+        * is not located on this node, return COPY_ABORTED with ASQ/ASQC
+        * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the
+        * initiator to fall back to normal copy method.
+        */
+       if (rc < 0) {
+               *sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
                goto out;
+       }
 
        pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n",
                 xop->src_dev, &xop->src_tid_wwn[0]);
@@ -653,6 +662,7 @@ static int target_xcopy_read_source(
        rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
                                remote_port, true);
        if (rc < 0) {
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                transport_generic_free_cmd(se_cmd, 0);
                return rc;
        }
@@ -664,6 +674,7 @@ static int target_xcopy_read_source(
 
        rc = target_xcopy_issue_pt_cmd(xpt_cmd);
        if (rc < 0) {
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                transport_generic_free_cmd(se_cmd, 0);
                return rc;
        }
@@ -714,6 +725,7 @@ static int target_xcopy_write_destination(
                                remote_port, false);
        if (rc < 0) {
                struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd;
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                /*
                 * If the failure happened before the t_mem_list hand-off in
                 * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that
@@ -729,6 +741,7 @@ static int target_xcopy_write_destination(
 
        rc = target_xcopy_issue_pt_cmd(xpt_cmd);
        if (rc < 0) {
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
                transport_generic_free_cmd(se_cmd, 0);
                return rc;
@@ -815,9 +828,14 @@ static void target_xcopy_do_work(struct work_struct *work)
 out:
        xcopy_pt_undepend_remotedev(xop);
        kfree(xop);
-
-       pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n");
-       ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+       /*
+        * Don't override an error scsi status if it has already been set
+        */
+       if (ec_cmd->scsi_status == SAM_STAT_GOOD) {
+               pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY"
+                       " CHECK_CONDITION -> sending response\n", rc);
+               ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+       }
        target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION);
 }
 
@@ -875,7 +893,7 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
                " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
                tdll, sdll, inline_dl);
 
-       rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll);
+       rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
        if (rc <= 0)
                goto out;
 
index 216e18cc9133d6709b25168610e98552b96d2647..ff5de9a96643f9b21e06a14af4bcd5e7277689f9 100644 (file)
@@ -572,10 +572,10 @@ static void ft_send_work(struct work_struct *work)
        if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
                              &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
                              ntohl(fcp->fc_dl), task_attr, data_dir,
-                             TARGET_SCF_ACK_KREF))
+                             TARGET_SCF_ACK_KREF | TARGET_SCF_USE_CPUID))
                goto err;
 
-       pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl);
+       pr_debug("r_ctl %x target_submit_cmd %p\n", fh->fh_r_ctl, cmd);
        return;
 
 err:
index 6ffbb603d9122a0259daa69db5bcca03ba891aa5..fd5c3de794705bb467f8689540f8045e61629d7f 100644 (file)
 
 #include "tcm_fc.h"
 
+#define TFC_SESS_DBG(lport, fmt, args...) \
+       pr_debug("host%u: rport %6.6x: " fmt,      \
+                (lport)->host->host_no,           \
+                (lport)->port_id, ##args )
+
 static void ft_sess_delete_all(struct ft_tport *);
 
 /*
@@ -167,24 +172,29 @@ static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id)
        struct ft_tport *tport;
        struct hlist_head *head;
        struct ft_sess *sess;
+       char *reason = "no session created";
 
        rcu_read_lock();
        tport = rcu_dereference(lport->prov[FC_TYPE_FCP]);
-       if (!tport)
+       if (!tport) {
+               reason = "not an FCP port";
                goto out;
+       }
 
        head = &tport->hash[ft_sess_hash(port_id)];
        hlist_for_each_entry_rcu(sess, head, hash) {
                if (sess->port_id == port_id) {
                        kref_get(&sess->kref);
                        rcu_read_unlock();
-                       pr_debug("port_id %x found %p\n", port_id, sess);
+                       TFC_SESS_DBG(lport, "port_id %x found %p\n",
+                                    port_id, sess);
                        return sess;
                }
        }
 out:
        rcu_read_unlock();
-       pr_debug("port_id %x not found\n", port_id);
+       TFC_SESS_DBG(lport, "port_id %x not found, %s\n",
+                    port_id, reason);
        return NULL;
 }
 
@@ -195,7 +205,7 @@ static int ft_sess_alloc_cb(struct se_portal_group *se_tpg,
        struct ft_tport *tport = sess->tport;
        struct hlist_head *head = &tport->hash[ft_sess_hash(sess->port_id)];
 
-       pr_debug("port_id %x sess %p\n", sess->port_id, sess);
+       TFC_SESS_DBG(tport->lport, "port_id %x sess %p\n", sess->port_id, sess);
        hlist_add_head_rcu(&sess->hash, head);
        tport->sess_count++;
 
@@ -223,7 +233,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
 
        sess = kzalloc(sizeof(*sess), GFP_KERNEL);
        if (!sess)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        kref_init(&sess->kref); /* ref for table entry */
        sess->tport = tport;
@@ -234,8 +244,9 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
                                             TARGET_PROT_NORMAL, &initiatorname[0],
                                             sess, ft_sess_alloc_cb);
        if (IS_ERR(sess->se_sess)) {
+               int rc = PTR_ERR(sess->se_sess);
                kfree(sess);
-               return NULL;
+               sess = ERR_PTR(rc);
        }
        return sess;
 }
@@ -319,7 +330,7 @@ void ft_sess_close(struct se_session *se_sess)
                mutex_unlock(&ft_lport_lock);
                return;
        }
-       pr_debug("port_id %x\n", port_id);
+       TFC_SESS_DBG(sess->tport->lport, "port_id %x close session\n", port_id);
        ft_sess_unhash(sess);
        mutex_unlock(&ft_lport_lock);
        ft_close_sess(sess);
@@ -379,8 +390,13 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
                if (!(fcp_parm & FCP_SPPF_INIT_FCN))
                        return FC_SPP_RESP_CONF;
                sess = ft_sess_create(tport, rdata->ids.port_id, rdata);
-               if (!sess)
-                       return FC_SPP_RESP_RES;
+               if (IS_ERR(sess)) {
+                       if (PTR_ERR(sess) == -EACCES) {
+                               spp->spp_flags &= ~FC_SPP_EST_IMG_PAIR;
+                               return FC_SPP_RESP_CONF;
+                       } else
+                               return FC_SPP_RESP_RES;
+               }
                if (!sess->params)
                        rdata->prli_count++;
                sess->params = fcp_parm;
@@ -423,8 +439,8 @@ static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len,
        mutex_lock(&ft_lport_lock);
        ret = ft_prli_locked(rdata, spp_len, rspp, spp);
        mutex_unlock(&ft_lport_lock);
-       pr_debug("port_id %x flags %x ret %x\n",
-              rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret);
+       TFC_SESS_DBG(rdata->local_port, "port_id %x flags %x ret %x\n",
+                    rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret);
        return ret;
 }
 
@@ -477,11 +493,11 @@ static void ft_recv(struct fc_lport *lport, struct fc_frame *fp)
        struct ft_sess *sess;
        u32 sid = fc_frame_sid(fp);
 
-       pr_debug("sid %x\n", sid);
+       TFC_SESS_DBG(lport, "recv sid %x\n", sid);
 
        sess = ft_sess_get(lport, sid);
        if (!sess) {
-               pr_debug("sid %x sess lookup failed\n", sid);
+               TFC_SESS_DBG(lport, "sid %x sess lookup failed\n", sid);
                /* TBD XXX - if FCP_CMND, send PRLO */
                fc_frame_free(fp);
                return;
index 9b4815e81b0df01cf2160d752499b670c4a2d731..19bf2028e508437e46c96e1a5df89e763f6cf59c 100644 (file)
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/acpi.h>
 #include <linux/thermal.h>
 #include <linux/pm.h>
 
 /* Intel PCH thermal Device IDs */
+#define PCH_THERMAL_DID_HSW_1  0x9C24 /* Haswell PCH */
+#define PCH_THERMAL_DID_HSW_2  0x8C24 /* Haswell PCH */
 #define PCH_THERMAL_DID_WPT    0x9CA4 /* Wildcat Point */
 #define PCH_THERMAL_DID_SKL    0x9D31 /* Skylake PCH */
 
@@ -66,9 +69,53 @@ struct pch_thermal_device {
        unsigned long crt_temp;
        int hot_trip_id;
        unsigned long hot_temp;
+       int psv_trip_id;
+       unsigned long psv_temp;
        bool bios_enabled;
 };
 
+#ifdef CONFIG_ACPI
+
+/*
+ * On some platforms, there is a companion ACPI device, which adds
+ * passive trip temperature using _PSV method. There is no specific
+ * passive temperature setting in MMIO interface of this PCI device.
+ */
+static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
+                                     int *nr_trips)
+{
+       struct acpi_device *adev;
+
+       ptd->psv_trip_id = -1;
+
+       adev = ACPI_COMPANION(&ptd->pdev->dev);
+       if (adev) {
+               unsigned long long r;
+               acpi_status status;
+
+               status = acpi_evaluate_integer(adev->handle, "_PSV", NULL,
+                                              &r);
+               if (ACPI_SUCCESS(status)) {
+                       unsigned long trip_temp;
+
+                       trip_temp = DECI_KELVIN_TO_MILLICELSIUS(r);
+                       if (trip_temp) {
+                               ptd->psv_temp = trip_temp;
+                               ptd->psv_trip_id = *nr_trips;
+                               ++(*nr_trips);
+                       }
+               }
+       }
+}
+#else
+static void pch_wpt_add_acpi_psv_trip(struct pch_thermal_device *ptd,
+                                     int *nr_trips)
+{
+       ptd->psv_trip_id = -1;
+
+}
+#endif
+
 static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips)
 {
        u8 tsel;
@@ -119,6 +166,8 @@ read_trips:
                ++(*nr_trips);
        }
 
+       pch_wpt_add_acpi_psv_trip(ptd, nr_trips);
+
        return 0;
 }
 
@@ -194,6 +243,8 @@ static int pch_get_trip_type(struct thermal_zone_device *tzd, int trip,
                *type = THERMAL_TRIP_CRITICAL;
        else if (ptd->hot_trip_id == trip)
                *type = THERMAL_TRIP_HOT;
+       else if (ptd->psv_trip_id == trip)
+               *type = THERMAL_TRIP_PASSIVE;
        else
                return -EINVAL;
 
@@ -208,6 +259,8 @@ static int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, int *tem
                *temp = ptd->crt_temp;
        else if (ptd->hot_trip_id == trip)
                *temp = ptd->hot_temp;
+       else if (ptd->psv_trip_id == trip)
+               *temp = ptd->psv_temp;
        else
                return -EINVAL;
 
@@ -242,6 +295,11 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev,
                ptd->ops = &pch_dev_ops_wpt;
                dev_name = "pch_skylake";
                break;
+       case PCH_THERMAL_DID_HSW_1:
+       case PCH_THERMAL_DID_HSW_2:
+               ptd->ops = &pch_dev_ops_wpt;
+               dev_name = "pch_haswell";
+               break;
        default:
                dev_err(&pdev->dev, "unknown pch thermal device\n");
                return -ENODEV;
@@ -324,6 +382,8 @@ static int intel_pch_thermal_resume(struct device *device)
 static struct pci_device_id intel_pch_thermal_id[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2) },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
index 0e4dc0afcfd244d510b003575249c4c3ce1d16bd..afada655f86198366b88b0d379a4bb79c8095bbb 100644 (file)
@@ -669,20 +669,17 @@ static struct thermal_cooling_device_ops powerclamp_cooling_ops = {
        .set_cur_state = powerclamp_set_cur_state,
 };
 
-static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = {
+static const struct x86_cpu_id __initconst intel_powerclamp_ids[] = {
        { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_MWAIT },
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ARAT },
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_NONSTOP_TSC },
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_CONSTANT_TSC},
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids);
 
 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",
-                               boot_cpu_data.x86, boot_cpu_data.x86_model);
+               pr_err("CPU does not support MWAIT");
                return -ENODEV;
        }
 
index 886fcf37f291ac7c78654aa2f3a511f976846732..b9923464599f6fc18b825d902fe8f14b5555e981 100644 (file)
@@ -213,7 +213,7 @@ static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
        struct pci_dev *pdev = to_pci_dev(port->dev);
        int ret;
 
-       ret = pci_alloc_irq_vectors(pdev, 1, 1, 0);
+       ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
        if (ret < 0)
                return ret;
 
index 1bfb6fdbaa20861a40599f6c33facbf615788b6d..1731b98d2471077c762806b63f88993b0a475fc3 100644 (file)
@@ -83,7 +83,8 @@ static const struct serial8250_config uart_config[] = {
                .name           = "16550A",
                .fifo_size      = 16,
                .tx_loadsz      = 16,
-               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+                                 UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
                .rxtrig_bytes   = {1, 4, 8, 14},
                .flags          = UART_CAP_FIFO,
        },
index b8d9c8c9d02a9762a2be77861554f13e49488a0c..417d9e7038e1aa53ea3da50569d158f7b88d4c78 100644 (file)
@@ -99,7 +99,7 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value)
        case UART_LCR:
                valshift = UNIPHIER_UART_LCR_SHIFT;
                /* Divisor latch access bit does not exist. */
-               value &= ~(UART_LCR_DLAB << valshift);
+               value &= ~UART_LCR_DLAB;
                /* fall through */
        case UART_MCR:
                offset = UNIPHIER_UART_LCR_MCR;
@@ -199,7 +199,7 @@ static int uniphier_uart_probe(struct platform_device *pdev)
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs) {
-               dev_err(dev, "failed to get memory resource");
+               dev_err(dev, "failed to get memory resource\n");
                return -EINVAL;
        }
 
index c7831407a882d2bb19be29153926d156a2a10a93..25c1d7bc010043b15f1676660bef7577150252cb 100644 (file)
@@ -1625,6 +1625,7 @@ config SERIAL_SPRD_CONSOLE
 config SERIAL_STM32
        tristate "STMicroelectronics STM32 serial port support"
        select SERIAL_CORE
+       depends on HAS_DMA
        depends on ARM || COMPILE_TEST
        help
          This driver is for the on-chip Serial Controller on
index fd8aa1f4ba782b62466dadea4868a0005f6fe5e2..168b10cad47b5437c2152313fcad026e2747300a 100644 (file)
@@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
                mode |= ATMEL_US_USMODE_RS485;
        } else if (termios->c_cflag & CRTSCTS) {
                /* RS232 with hardware handshake (RTS/CTS) */
-               if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
-                       dev_info(port->dev, "not enabling hardware flow control because DMA is used");
-                       termios->c_cflag &= ~CRTSCTS;
-               } else {
+               if (atmel_use_fifo(port) &&
+                   !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
+                       /*
+                        * with ATMEL_US_USMODE_HWHS set, the controller will
+                        * be able to drive the RTS pin high/low when the RX
+                        * FIFO is above RXFTHRES/below RXFTHRES2.
+                        * It will also disable the transmitter when the CTS
+                        * pin is high.
+                        * This mode is not activated if CTS pin is a GPIO
+                        * because in this case, the transmitter is always
+                        * disabled (there must be an internal pull-up
+                        * responsible for this behaviour).
+                        * If the RTS pin is a GPIO, the controller won't be
+                        * able to drive it according to the FIFO thresholds,
+                        * but it will be handled by the driver.
+                        */
                        mode |= ATMEL_US_USMODE_HWHS;
+               } else {
+                       /*
+                        * For platforms without FIFO, the flow control is
+                        * handled by the driver.
+                        */
+                       mode |= ATMEL_US_USMODE_NORMAL;
                }
        } else {
                /* RS232 without hadware handshake */
index de9d5107c00a0e1430b9ad8f8dfb99b7d4b2c9b3..76103f2c4a8001e36e10fffc7581ee2ee4c885b6 100644 (file)
@@ -328,7 +328,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
 
        sport->dma_tx_bytes = uart_circ_chars_pending(xmit);
 
-       if (xmit->tail < xmit->head) {
+       if (xmit->tail < xmit->head || xmit->head == 0) {
                sport->dma_tx_nents = 1;
                sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes);
        } else {
@@ -359,7 +359,6 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
        sport->dma_tx_in_progress = true;
        sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
        dma_async_issue_pending(sport->dma_tx_chan);
-
 }
 
 static void lpuart_dma_tx_complete(void *arg)
index d391650b82e7be9bb63ac7df85a9de3e4fe0bed8..42caccb5e87eeabf732872225ef1527f427acea6 100644 (file)
@@ -419,6 +419,7 @@ static struct dmi_system_id pch_uart_dmi_table[] = {
                },
                (void *)MINNOW_UARTCLK,
        },
+       { }
 };
 
 /* Return UART clock, checking for board specific clocks. */
index 2675792a8f5963a37b82d708b0ce87f8f070d5dd..fb0672554123a196d75fd9eedca35a915ddc12e6 100644 (file)
@@ -1130,9 +1130,13 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
 {
        struct sc16is7xx_port *s = gpiochip_get_data(chip);
        struct uart_port *port = &s->p[0].port;
+       u8 state = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG);
 
-       sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
-                             val ? BIT(offset) : 0);
+       if (val)
+               state |= BIT(offset);
+       else
+               state &= ~BIT(offset);
+       sc16is7xx_port_write(port, SC16IS7XX_IOSTATE_REG, state);
        sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset),
                              BIT(offset));
 
index 6e4f63627479db8d33547ef18fd1e6e365f5bdb7..f2303f390345e14664f31976662f7c804fbbb9d9 100644 (file)
@@ -111,7 +111,7 @@ void uart_write_wakeup(struct uart_port *port)
         * closed.  No cookie for you.
         */
        BUG_ON(!state);
-       tty_wakeup(state->port.tty);
+       tty_port_tty_wakeup(&state->port);
 }
 
 static void uart_stop(struct tty_struct *tty)
@@ -632,7 +632,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
        if (port->ops->flush_buffer)
                port->ops->flush_buffer(port);
        uart_port_unlock(port, flags);
-       tty_wakeup(tty);
+       tty_port_tty_wakeup(&state->port);
 }
 
 /*
@@ -2746,8 +2746,6 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
        uport->cons = drv->cons;
        uport->minor = drv->tty_driver->minor_start + uport->line;
 
-       port->console = uart_console(uport);
-
        /*
         * If this port is a console, then the spinlock is already
         * initialised.
@@ -2761,6 +2759,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
 
        uart_configure_port(drv, state, uport);
 
+       port->console = uart_console(uport);
+
        num_groups = 2;
        if (uport->attr_group)
                num_groups++;
index 41d97492310271dbb3f2036d484b7b2ae5ee8c10..cd97ceb76e4ffe6f48af1a614532bdf42318e2de 100644 (file)
@@ -31,7 +31,7 @@ struct stm32_usart_info {
        struct stm32_usart_config cfg;
 };
 
-#define UNDEF_REG ~0
+#define UNDEF_REG 0xff
 
 /* Register offsets */
 struct stm32_usart_info stm32f4_info = {
index f37edaa5ac7577ed77c944d68e1fed7f526674e9..dd4c02fa4820a2f9c07c9ddfafd7fd7dd6be1fea 100644 (file)
@@ -1200,6 +1200,7 @@ static int __init cdns_early_console_setup(struct earlycon_device *device,
 OF_EARLYCON_DECLARE(cdns, "xlnx,xuartps", cdns_early_console_setup);
 OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup);
 OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup);
+OF_EARLYCON_DECLARE(cdns, "xlnx,zynqmp-uart", cdns_early_console_setup);
 
 /**
  * cdns_uart_console_write - perform write operation
@@ -1438,6 +1439,7 @@ static const struct of_device_id cdns_uart_of_match[] = {
        { .compatible = "xlnx,xuartps", },
        { .compatible = "cdns,uart-r1p8", },
        { .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def },
+       { .compatible = "xlnx,zynqmp-uart", .data = &zynqmp_uart_def },
        {}
 };
 MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
index 06fb39c1d6dd5e06fb7541030d881d9999813771..8c3bf3d613c061615bbcf15a607f371e9208c67b 100644 (file)
@@ -870,10 +870,15 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
        if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
                return 0;
 
+       if (new_screen_size > (4 << 20))
+               return -EINVAL;
        newscreen = kmalloc(new_screen_size, GFP_USER);
        if (!newscreen)
                return -ENOMEM;
 
+       if (vc == sel_cons)
+               clear_selection();
+
        old_rows = vc->vc_rows;
        old_row_size = vc->vc_size_row;
 
@@ -1176,7 +1181,7 @@ static void csi_J(struct vc_data *vc, int vpar)
                        break;
                case 3: /* erase scroll-back buffer (and whole display) */
                        scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
-                                   vc->vc_screenbuf_size >> 1);
+                                   vc->vc_screenbuf_size);
                        set_origin(vc);
                        if (con_is_visible(vc))
                                update_screen(vc);
index 69426e644d17019b1c6e2d672b2e1a04cbffc3fd..3dbb4a21ab44c8a6555f5e2ad2a321a61526e23b 100644 (file)
@@ -914,6 +914,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
        if (!ci)
                return -ENOMEM;
 
+       spin_lock_init(&ci->lock);
        ci->dev = dev;
        ci->platdata = dev_get_platdata(dev);
        ci->imx28_write_fix = !!(ci->platdata->flags &
index 96ae69502c86fac5b1b2f7306f049d7f7bb5085f..111b0e0b8698b76d0de983e856c89dadea92734e 100644 (file)
@@ -188,6 +188,8 @@ static void host_stop(struct ci_hdrc *ci)
 
        if (hcd) {
                usb_remove_hcd(hcd);
+               ci->role = CI_ROLE_END;
+               synchronize_irq(ci->irq);
                usb_put_hcd(hcd);
                if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) &&
                        (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON))
index 661f43fe0f9e9e8f9d9be29eaed5bb1307b8df54..c9e80ad48fdcdb0912271a336600167ff91d7276 100644 (file)
@@ -1889,8 +1889,6 @@ static int udc_start(struct ci_hdrc *ci)
        struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
        int retval = 0;
 
-       spin_lock_init(&ci->lock);
-
        ci->gadget.ops          = &usb_gadget_ops;
        ci->gadget.speed        = USB_SPEED_UNKNOWN;
        ci->gadget.max_speed    = USB_SPEED_HIGH;
index 78f0f85bebdc25ef971405175feb621865f4cad1..fada988512a1622a9551a5d6d5ae7482d78ac35f 100644 (file)
@@ -932,8 +932,6 @@ static int wait_serial_change(struct acm *acm, unsigned long arg)
        DECLARE_WAITQUEUE(wait, current);
        struct async_icount old, new;
 
-       if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD))
-               return -EINVAL;
        do {
                spin_lock_irq(&acm->read_lock);
                old = acm->oldcount;
@@ -1161,6 +1159,8 @@ static int acm_probe(struct usb_interface *intf,
        if (quirks == IGNORE_DEVICE)
                return -ENODEV;
 
+       memset(&h, 0x00, sizeof(struct usb_cdc_parsed_header));
+
        num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
 
        /* handle quirks deadly to normal probing*/
index fa9b26b915071ada49ee1b068ff098c09a962ff1..4c0fa0b173538847e680ae13e983d6a3534311d6 100644 (file)
@@ -463,9 +463,18 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
  */
 void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
 {
+       bool ret;
+
        switch (hsotg->dr_mode) {
        case USB_DR_MODE_HOST:
-               dwc2_force_mode(hsotg, true);
+               ret = dwc2_force_mode(hsotg, true);
+               /*
+                * NOTE: This is required for some rockchip soc based
+                * platforms on their host-only dwc2.
+                */
+               if (!ret)
+                       msleep(50);
+
                break;
        case USB_DR_MODE_PERIPHERAL:
                dwc2_force_mode(hsotg, false);
index aad4107ef927e26388f302ebbbd7907ad9a295c0..2a21a0414b1d385347ac700b4db5fda2f502c523 100644 (file)
@@ -259,6 +259,13 @@ enum dwc2_lx_state {
        DWC2_L3,        /* Off state */
 };
 
+/*
+ * Gadget periodic tx fifo sizes as used by legacy driver
+ * EP0 is not included
+ */
+#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
+                                          768, 0, 0, 0, 0, 0, 0, 0}
+
 /* Gadget ep0 states */
 enum dwc2_ep0_state {
        DWC2_EP0_SETUP,
index 4cd6403a75668c35bef6a277f987bf41fc55ed27..24fbebc9b409050092c8a54296c445f129422e83 100644 (file)
@@ -186,10 +186,9 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg,
  */
 static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
 {
-       unsigned int fifo;
+       unsigned int ep;
        unsigned int addr;
        int timeout;
-       u32 dptxfsizn;
        u32 val;
 
        /* Reset fifo map if not correctly cleared during previous session */
@@ -217,16 +216,16 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
         * them to endpoints dynamically according to maxpacket size value of
         * given endpoint.
         */
-       for (fifo = 1; fifo < MAX_EPS_CHANNELS; fifo++) {
-               dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(fifo));
-
-               val = (dptxfsizn & FIFOSIZE_DEPTH_MASK) | addr;
-               addr += dptxfsizn >> FIFOSIZE_DEPTH_SHIFT;
-
-               if (addr > hsotg->fifo_mem)
-                       break;
+       for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) {
+               if (!hsotg->g_tx_fifo_sz[ep])
+                       continue;
+               val = addr;
+               val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT;
+               WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem,
+                         "insufficient fifo memory");
+               addr += hsotg->g_tx_fifo_sz[ep];
 
-               dwc2_writel(val, hsotg->regs + DPTXFSIZN(fifo));
+               dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep));
        }
 
        /*
@@ -3807,10 +3806,36 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg)
 static void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg)
 {
        struct device_node *np = hsotg->dev->of_node;
+       u32 len = 0;
+       u32 i = 0;
 
        /* Enable dma if requested in device tree */
        hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma");
 
+       /*
+       * Register TX periodic fifo size per endpoint.
+       * EP0 is excluded since it has no fifo configuration.
+       */
+       if (!of_find_property(np, "g-tx-fifo-size", &len))
+               goto rx_fifo;
+
+       len /= sizeof(u32);
+
+       /* Read tx fifo sizes other than ep0 */
+       if (of_property_read_u32_array(np, "g-tx-fifo-size",
+                                               &hsotg->g_tx_fifo_sz[1], len))
+               goto rx_fifo;
+
+       /* Add ep0 */
+       len++;
+
+       /* Make remaining TX fifos unavailable */
+       if (len < MAX_EPS_CHANNELS) {
+               for (i = len; i < MAX_EPS_CHANNELS; i++)
+                       hsotg->g_tx_fifo_sz[i] = 0;
+       }
+
+rx_fifo:
        /* Register RX fifo size */
        of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz);
 
@@ -3832,10 +3857,13 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
        struct device *dev = hsotg->dev;
        int epnum;
        int ret;
+       int i;
+       u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE;
 
        /* Initialize to legacy fifo configuration values */
        hsotg->g_rx_fifo_sz = 2048;
        hsotg->g_np_g_tx_fifo_sz = 1024;
+       memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo));
        /* Device tree specific probe */
        dwc2_hsotg_of_probe(hsotg);
 
@@ -3853,6 +3881,9 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
        dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
                                                hsotg->g_np_g_tx_fifo_sz);
        dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz);
+       for (i = 0; i < MAX_EPS_CHANNELS; i++)
+               dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i,
+                                               hsotg->g_tx_fifo_sz[i]);
 
        hsotg->gadget.max_speed = USB_SPEED_HIGH;
        hsotg->gadget.ops = &dwc2_hsotg_gadget_ops;
index 7287a763cd0cc4ca5a114ed687e6c34b0bdd643d..fea446900cadd06dcf857bb9cdaa3c9b0ba79025 100644 (file)
@@ -769,15 +769,14 @@ static int dwc3_core_init(struct dwc3 *dwc)
        return 0;
 
 err4:
-       phy_power_off(dwc->usb2_generic_phy);
+       phy_power_off(dwc->usb3_generic_phy);
 
 err3:
-       phy_power_off(dwc->usb3_generic_phy);
+       phy_power_off(dwc->usb2_generic_phy);
 
 err2:
        usb_phy_set_suspend(dwc->usb2_phy, 1);
        usb_phy_set_suspend(dwc->usb3_phy, 1);
-       dwc3_core_exit(dwc);
 
 err1:
        usb_phy_shutdown(dwc->usb2_phy);
index 89a2f712fdfe32f5fc0a6fc0681b0d8db005e2a2..aaaf256f71dd63091aec15f0e6b64eaec03ef8f0 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/usb/of.h>
 
 #include "core.h"
index 07cc8929f27134e40b1084389fb3efb3c29c58f6..1dfa56a5f1c511a6a40f38cb976ed1096af3c5db 100644 (file)
@@ -783,6 +783,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                req->trb = trb;
                req->trb_dma = dwc3_trb_dma_offset(dep, trb);
                req->first_trb_index = dep->trb_enqueue;
+               dep->queued_requests++;
        }
 
        dwc3_ep_inc_enq(dep);
@@ -833,8 +834,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 
        trb->ctrl |= DWC3_TRB_CTRL_HWO;
 
-       dep->queued_requests++;
-
        trace_dwc3_prepare_trb(dep, trb);
 }
 
@@ -1074,9 +1073,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 
        list_add_tail(&req->list, &dep->pending_list);
 
-       if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-                       dep->flags & DWC3_EP_PENDING_REQUEST) {
-               if (list_empty(&dep->started_list)) {
+       /*
+        * NOTICE: Isochronous endpoints should NEVER be prestarted. We must
+        * wait for a XferNotReady event so we will know what's the current
+        * (micro-)frame number.
+        *
+        * Without this trick, we are very, very likely gonna get Bus Expiry
+        * errors which will force us issue EndTransfer command.
+        */
+       if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+               if ((dep->flags & DWC3_EP_PENDING_REQUEST) &&
+                               list_empty(&dep->started_list)) {
                        dwc3_stop_active_transfer(dwc, dep->number, true);
                        dep->flags = DWC3_EP_ENABLED;
                }
@@ -1861,8 +1868,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
        unsigned int            s_pkt = 0;
        unsigned int            trb_status;
 
-       dep->queued_requests--;
        dwc3_ep_inc_deq(dep);
+
+       if (req->trb == trb)
+               dep->queued_requests--;
+
        trace_dwc3_complete_trb(dep, trb);
 
        /*
@@ -2980,7 +2990,7 @@ err3:
        kfree(dwc->setup_buf);
 
 err2:
-       dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+       dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
                        dwc->ep0_trb, dwc->ep0_trb_addr);
 
 err1:
@@ -3005,7 +3015,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
        kfree(dwc->setup_buf);
        kfree(dwc->zlp_buf);
 
-       dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+       dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
                        dwc->ep0_trb, dwc->ep0_trb_addr);
 
        dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
index 54ad100af35b487758460089ce476b7aaab4d07f..17989b72cdaec18dbf55d0709897fc75d1842ab7 100644 (file)
@@ -136,8 +136,60 @@ struct ffs_epfile {
        /*
         * Buffer for holding data from partial reads which may happen since
         * we’re rounding user read requests to a multiple of a max packet size.
+        *
+        * The pointer is initialised with NULL value and may be set by
+        * __ffs_epfile_read_data function to point to a temporary buffer.
+        *
+        * In normal operation, calls to __ffs_epfile_read_buffered will consume
+        * data from said buffer and eventually free it.  Importantly, while the
+        * function is using the buffer, it sets the pointer to NULL.  This is
+        * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered
+        * can never run concurrently (they are synchronised by epfile->mutex)
+        * so the latter will not assign a new value to the pointer.
+        *
+        * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is
+        * valid) and sets the pointer to READ_BUFFER_DROP value.  This special
+        * value is crux of the synchronisation between ffs_func_eps_disable and
+        * __ffs_epfile_read_data.
+        *
+        * Once __ffs_epfile_read_data is about to finish it will try to set the
+        * pointer back to its old value (as described above), but seeing as the
+        * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free
+        * the buffer.
+        *
+        * == State transitions ==
+        *
+        * â€¢ ptr == NULL:  (initial state)
+        *   â—¦ __ffs_epfile_read_buffer_free: go to ptr == DROP
+        *   â—¦ __ffs_epfile_read_buffered:    nop
+        *   â—¦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf
+        *   â—¦ reading finishes:              n/a, not in â€˜and reading’ state
+        * â€¢ ptr == DROP:
+        *   â—¦ __ffs_epfile_read_buffer_free: nop
+        *   â—¦ __ffs_epfile_read_buffered:    go to ptr == NULL
+        *   â—¦ __ffs_epfile_read_data allocates temp buffer: free buf, nop
+        *   â—¦ reading finishes:              n/a, not in â€˜and reading’ state
+        * â€¢ ptr == buf:
+        *   â—¦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP
+        *   â—¦ __ffs_epfile_read_buffered:    go to ptr == NULL and reading
+        *   â—¦ __ffs_epfile_read_data:        n/a, __ffs_epfile_read_buffered
+        *                                    is always called first
+        *   â—¦ reading finishes:              n/a, not in â€˜and reading’ state
+        * â€¢ ptr == NULL and reading:
+        *   â—¦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading
+        *   â—¦ __ffs_epfile_read_buffered:    n/a, mutex is held
+        *   â—¦ __ffs_epfile_read_data:        n/a, mutex is held
+        *   â—¦ reading finishes and â€¦
+        *     â€¦ all data read:               free buf, go to ptr == NULL
+        *     â€¦ otherwise:                   go to ptr == buf and reading
+        * â€¢ ptr == DROP and reading:
+        *   â—¦ __ffs_epfile_read_buffer_free: nop
+        *   â—¦ __ffs_epfile_read_buffered:    n/a, mutex is held
+        *   â—¦ __ffs_epfile_read_data:        n/a, mutex is held
+        *   â—¦ reading finishes:              free buf, go to ptr == DROP
         */
-       struct ffs_buffer               *read_buffer;   /* P: epfile->mutex */
+       struct ffs_buffer               *read_buffer;
+#define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN))
 
        char                            name[5];
 
@@ -736,25 +788,47 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
        schedule_work(&io_data->work);
 }
 
+static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
+{
+       /*
+        * See comment in struct ffs_epfile for full read_buffer pointer
+        * synchronisation story.
+        */
+       struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP);
+       if (buf && buf != READ_BUFFER_DROP)
+               kfree(buf);
+}
+
 /* Assumes epfile->mutex is held. */
 static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
                                          struct iov_iter *iter)
 {
-       struct ffs_buffer *buf = epfile->read_buffer;
+       /*
+        * Null out epfile->read_buffer so ffs_func_eps_disable does not free
+        * the buffer while we are using it.  See comment in struct ffs_epfile
+        * for full read_buffer pointer synchronisation story.
+        */
+       struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL);
        ssize_t ret;
-       if (!buf)
+       if (!buf || buf == READ_BUFFER_DROP)
                return 0;
 
        ret = copy_to_iter(buf->data, buf->length, iter);
        if (buf->length == ret) {
                kfree(buf);
-               epfile->read_buffer = NULL;
-       } else if (unlikely(iov_iter_count(iter))) {
+               return ret;
+       }
+
+       if (unlikely(iov_iter_count(iter))) {
                ret = -EFAULT;
        } else {
                buf->length -= ret;
                buf->data += ret;
        }
+
+       if (cmpxchg(&epfile->read_buffer, NULL, buf))
+               kfree(buf);
+
        return ret;
 }
 
@@ -783,7 +857,15 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
        buf->length = data_len;
        buf->data = buf->storage;
        memcpy(buf->storage, data + ret, data_len);
-       epfile->read_buffer = buf;
+
+       /*
+        * At this point read_buffer is NULL or READ_BUFFER_DROP (if
+        * ffs_func_eps_disable has been called in the meanwhile).  See comment
+        * in struct ffs_epfile for full read_buffer pointer synchronisation
+        * story.
+        */
+       if (unlikely(cmpxchg(&epfile->read_buffer, NULL, buf)))
+               kfree(buf);
 
        return ret;
 }
@@ -1097,8 +1179,7 @@ ffs_epfile_release(struct inode *inode, struct file *file)
 
        ENTER();
 
-       kfree(epfile->read_buffer);
-       epfile->read_buffer = NULL;
+       __ffs_epfile_read_buffer_free(epfile);
        ffs_data_closed(epfile->ffs);
 
        return 0;
@@ -1724,24 +1805,20 @@ static void ffs_func_eps_disable(struct ffs_function *func)
        unsigned count            = func->ffs->eps_count;
        unsigned long flags;
 
+       spin_lock_irqsave(&func->ffs->eps_lock, flags);
        do {
-               if (epfile)
-                       mutex_lock(&epfile->mutex);
-               spin_lock_irqsave(&func->ffs->eps_lock, flags);
                /* pending requests get nuked */
                if (likely(ep->ep))
                        usb_ep_disable(ep->ep);
                ++ep;
-               spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
 
                if (epfile) {
                        epfile->ep = NULL;
-                       kfree(epfile->read_buffer);
-                       epfile->read_buffer = NULL;
-                       mutex_unlock(&epfile->mutex);
+                       __ffs_epfile_read_buffer_free(epfile);
                        ++epfile;
                }
        } while (--count);
+       spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
 }
 
 static int ffs_func_eps_enable(struct ffs_function *func)
@@ -3148,11 +3225,11 @@ static bool ffs_func_req_match(struct usb_function *f,
 
        switch (creq->bRequestType & USB_RECIP_MASK) {
        case USB_RECIP_INTERFACE:
-               return ffs_func_revmap_intf(func,
-                                           le16_to_cpu(creq->wIndex) >= 0);
+               return (ffs_func_revmap_intf(func,
+                                            le16_to_cpu(creq->wIndex)) >= 0);
        case USB_RECIP_ENDPOINT:
-               return ffs_func_revmap_ep(func,
-                                         le16_to_cpu(creq->wIndex) >= 0);
+               return (ffs_func_revmap_ep(func,
+                                          le16_to_cpu(creq->wIndex)) >= 0);
        default:
                return (bool) (func->ffs->user_flags &
                               FUNCTIONFS_ALL_CTRL_RECIP);
index 9c8c9ed1dc9e0b2186e60e66488ea1159f22d7b8..5d1bd13a56c11f61b50c0b0ec4a772311946672b 100644 (file)
@@ -588,13 +588,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
 
        req->length = length;
 
-       /* throttle high/super speed IRQ rate back slightly */
-       if (gadget_is_dualspeed(dev->gadget))
-               req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
-                                    dev->gadget->speed == USB_SPEED_SUPER)
-                       ? ((atomic_read(&dev->tx_qlen) % dev->qmult) != 0)
-                       : 0;
-
        retval = usb_ep_queue(in, req, GFP_ATOMIC);
        switch (retval) {
        default:
index bb1f6c8f0f01ab492c6b5c0d1852c655d2cc26ee..45bc997d071131c1e7ef51c3968dd5e295994f44 100644 (file)
@@ -1978,7 +1978,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
                        dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret);
                        goto err;
                }
-               ep->ep.name = name;
+               ep->ep.name = kasprintf(GFP_KERNEL, "ep%d", ep->index);
 
                ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
                ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
index 876dca4fc2162520603afdfd430e26d54b82531f..a268d9e8d6cfb17b214278e23c44267cf8c06e33 100644 (file)
@@ -39,7 +39,7 @@
 
 #define DRIVER_DESC "EHCI generic platform driver"
 #define EHCI_MAX_CLKS 4
-#define EHCI_MAX_RSTS 3
+#define EHCI_MAX_RSTS 4
 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
 
 struct ehci_platform_priv {
index 5b5880c0ae1916d14c1ce997b8be9d3c2a9d3798..b38a228134df108d148037232126e815d9557a7b 100644 (file)
@@ -221,6 +221,12 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
        ohci->num_ports = board->ports;
        at91_start_hc(pdev);
 
+       /*
+        * The RemoteWakeupConnected bit has to be set explicitly
+        * before calling ohci_run. The reset value of this bit is 0.
+        */
+       ohci->hc_control = OHCI_CTRL_RWC;
+
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval == 0) {
                device_wakeup_enable(hcd->self.controller);
@@ -677,9 +683,6 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
         * REVISIT: some boards will be able to turn VBUS off...
         */
        if (!ohci_at91->wakeup) {
-               ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
-               ohci->hc_control &= OHCI_CTRL_RWC;
-               ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
                ohci->rh_state = OHCI_RH_HALTED;
 
                /* flush the writes */
index 1700908b84ef8b7c15716f07e448345f25fae392..86612ac3fda220e3d1c9b1b5c959f45f723d543d 100644 (file)
@@ -72,7 +72,7 @@
 static const char      hcd_name [] = "ohci_hcd";
 
 #define        STATECHANGE_DELAY       msecs_to_jiffies(300)
-#define        IO_WATCHDOG_DELAY       msecs_to_jiffies(250)
+#define        IO_WATCHDOG_DELAY       msecs_to_jiffies(275)
 
 #include "ohci.h"
 #include "pci-quirks.h"
index d793f548dfe26aef387d13b703454abe67beb5be..a9a1e4c40480cf2c5c7c7995aa5d337d3ef3ee87 100644 (file)
@@ -995,6 +995,14 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
        }
        val = readl(base + ext_cap_offset);
 
+       /* Auto handoff never worked for these devices. Force it and continue */
+       if ((pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241) ||
+                       (pdev->vendor == PCI_VENDOR_ID_RENESAS
+                        && pdev->device == 0x0014)) {
+               val = (val | XHCI_HC_OS_OWNED) & ~XHCI_HC_BIOS_OWNED;
+               writel(val, base + ext_cap_offset);
+       }
+
        /* If the BIOS owns the HC, signal that the OS wants it, and wait */
        if (val & XHCI_HC_BIOS_OWNED) {
                writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
index 730b9fd266852db5812e98456c9ff8299aa40ae6..0ef16900efedd7783489ade75594b4d0da798318 100644 (file)
@@ -1166,7 +1166,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                xhci_set_link_state(xhci, port_array, wIndex,
                                                        XDEV_RESUME);
                                spin_unlock_irqrestore(&xhci->lock, flags);
-                               msleep(20);
+                               msleep(USB_RESUME_TIMEOUT);
                                spin_lock_irqsave(&xhci->lock, flags);
                                xhci_set_link_state(xhci, port_array, wIndex,
                                                        XDEV_U0);
@@ -1355,6 +1355,35 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
        return 0;
 }
 
+/*
+ * Workaround for missing Cold Attach Status (CAS) if device re-plugged in S3.
+ * warm reset a USB3 device stuck in polling or compliance mode after resume.
+ * See Intel 100/c230 series PCH specification update Doc #332692-006 Errata #8
+ */
+static bool xhci_port_missing_cas_quirk(int port_index,
+                                            __le32 __iomem **port_array)
+{
+       u32 portsc;
+
+       portsc = readl(port_array[port_index]);
+
+       /* if any of these are set we are not stuck */
+       if (portsc & (PORT_CONNECT | PORT_CAS))
+               return false;
+
+       if (((portsc & PORT_PLS_MASK) != XDEV_POLLING) &&
+           ((portsc & PORT_PLS_MASK) != XDEV_COMP_MODE))
+               return false;
+
+       /* clear wakeup/change bits, and do a warm port reset */
+       portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
+       portsc |= PORT_WR;
+       writel(portsc, port_array[port_index]);
+       /* flush write */
+       readl(port_array[port_index]);
+       return true;
+}
+
 int xhci_bus_resume(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -1392,6 +1421,14 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                u32 temp;
 
                temp = readl(port_array[port_index]);
+
+               /* warm reset CAS limited ports stuck in polling/compliance */
+               if ((xhci->quirks & XHCI_MISSING_CAS) &&
+                   (hcd->speed >= HCD_USB3) &&
+                   xhci_port_missing_cas_quirk(port_index, port_array)) {
+                       xhci_dbg(xhci, "reset stuck port %d\n", port_index);
+                       continue;
+               }
                if (DEV_SUPERSPEED_ANY(temp))
                        temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
                else
@@ -1410,7 +1447,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
 
        if (need_usb2_u3_exit) {
                spin_unlock_irqrestore(&xhci->lock, flags);
-               msleep(20);
+               msleep(USB_RESUME_TIMEOUT);
                spin_lock_irqsave(&xhci->lock, flags);
        }
 
index d7b0f97abbad608200cbfb5b59d0faacfa1b8b43..e96ae80d107e94fd8db8c33cae52ff9153f14730 100644 (file)
 
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI     0x8c31
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI  0x9c31
+#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI       0x9cb1
 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI            0x22b5
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI                0xa12f
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI       0x9d2f
 #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI             0x0aa8
 #define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI             0x1aa8
+#define PCI_DEVICE_ID_INTEL_APL_XHCI                   0x5aa8
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -153,7 +155,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
        }
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
-               pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) {
+               (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI)) {
                xhci->quirks |= XHCI_SPURIOUS_REBOOT;
                xhci->quirks |= XHCI_SPURIOUS_WAKEUP;
        }
@@ -169,6 +172,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
                xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
        }
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+           (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
+               xhci->quirks |= XHCI_MISSING_CAS;
+
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_EJ168) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
index b2c1dc5dc0f30f17fa2f4354537c193958ab5f78..f945380035d07e2f7af2bb73da9d39bf94475991 100644 (file)
@@ -314,6 +314,8 @@ struct xhci_op_regs {
 #define XDEV_U2                (0x2 << 5)
 #define XDEV_U3                (0x3 << 5)
 #define XDEV_INACTIVE  (0x6 << 5)
+#define XDEV_POLLING   (0x7 << 5)
+#define XDEV_COMP_MODE  (0xa << 5)
 #define XDEV_RESUME    (0xf << 5)
 /* true: port has power (see HCC_PPC) */
 #define PORT_POWER     (1 << 9)
@@ -1653,6 +1655,7 @@ struct xhci_hcd {
 #define XHCI_MTK_HOST          (1 << 21)
 #define XHCI_SSIC_PORT_UNUSED  (1 << 22)
 #define XHCI_NO_64BIT_SUPPORT  (1 << 23)
+#define XHCI_MISSING_CAS       (1 << 24)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
index 210b7e43a6fd40bb6a626a9f300fc2bbe1eb0200..2440f88e07a35781433ba501fd60d8cf0b246431 100644 (file)
@@ -479,7 +479,8 @@ static int da8xx_probe(struct platform_device *pdev)
 
        glue->phy = devm_phy_get(&pdev->dev, "usb-phy");
        if (IS_ERR(glue->phy)) {
-               dev_err(&pdev->dev, "failed to get phy\n");
+               if (PTR_ERR(glue->phy) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get phy\n");
                return PTR_ERR(glue->phy);
        }
 
index 27dadc0d9114bf14d6034906153d7f1df60be4a5..c3e172e15ec3d9d9ec7346b972b2702fed710c65 100644 (file)
@@ -986,7 +986,7 @@ b_host:
        }
 #endif
 
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
 
        return handled;
 }
@@ -1855,14 +1855,23 @@ static void musb_pm_runtime_check_session(struct musb *musb)
                MUSB_DEVCTL_HR;
        switch (devctl & ~s) {
        case MUSB_QUIRK_B_INVALID_VBUS_91:
-               if (!musb->session && !musb->quirk_invalid_vbus) {
-                       musb->quirk_invalid_vbus = true;
+               if (musb->quirk_retries--) {
                        musb_dbg(musb,
-                                "First invalid vbus, assume no session");
+                                "Poll devctl on invalid vbus, assume no session");
+                       schedule_delayed_work(&musb->irq_work,
+                                             msecs_to_jiffies(1000));
+
                        return;
                }
-               break;
        case MUSB_QUIRK_A_DISCONNECT_19:
+               if (musb->quirk_retries--) {
+                       musb_dbg(musb,
+                                "Poll devctl on possible host mode disconnect");
+                       schedule_delayed_work(&musb->irq_work,
+                                             msecs_to_jiffies(1000));
+
+                       return;
+               }
                if (!musb->session)
                        break;
                musb_dbg(musb, "Allow PM on possible host mode disconnect");
@@ -1886,9 +1895,9 @@ static void musb_pm_runtime_check_session(struct musb *musb)
                if (error < 0)
                        dev_err(musb->controller, "Could not enable: %i\n",
                                error);
+               musb->quirk_retries = 3;
        } else {
                musb_dbg(musb, "Allow PM with no session: %02x", devctl);
-               musb->quirk_invalid_vbus = false;
                pm_runtime_mark_last_busy(musb->controller);
                pm_runtime_put_autosuspend(musb->controller);
        }
@@ -1899,7 +1908,7 @@ static void musb_pm_runtime_check_session(struct musb *musb)
 /* Only used to provide driver mode change events */
 static void musb_irq_work(struct work_struct *data)
 {
-       struct musb *musb = container_of(data, struct musb, irq_work);
+       struct musb *musb = container_of(data, struct musb, irq_work.work);
 
        musb_pm_runtime_check_session(musb);
 
@@ -1969,6 +1978,7 @@ static struct musb *allocate_instance(struct device *dev,
        INIT_LIST_HEAD(&musb->control);
        INIT_LIST_HEAD(&musb->in_bulk);
        INIT_LIST_HEAD(&musb->out_bulk);
+       INIT_LIST_HEAD(&musb->pending_list);
 
        musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
        musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
@@ -2018,6 +2028,84 @@ static void musb_free(struct musb *musb)
        musb_host_free(musb);
 }
 
+struct musb_pending_work {
+       int (*callback)(struct musb *musb, void *data);
+       void *data;
+       struct list_head node;
+};
+
+/*
+ * Called from musb_runtime_resume(), musb_resume(), and
+ * musb_queue_resume_work(). Callers must take musb->lock.
+ */
+static int musb_run_resume_work(struct musb *musb)
+{
+       struct musb_pending_work *w, *_w;
+       unsigned long flags;
+       int error = 0;
+
+       spin_lock_irqsave(&musb->list_lock, flags);
+       list_for_each_entry_safe(w, _w, &musb->pending_list, node) {
+               if (w->callback) {
+                       error = w->callback(musb, w->data);
+                       if (error < 0) {
+                               dev_err(musb->controller,
+                                       "resume callback %p failed: %i\n",
+                                       w->callback, error);
+                       }
+               }
+               list_del(&w->node);
+               devm_kfree(musb->controller, w);
+       }
+       spin_unlock_irqrestore(&musb->list_lock, flags);
+
+       return error;
+}
+
+/*
+ * Called to run work if device is active or else queue the work to happen
+ * on resume. Caller must take musb->lock and must hold an RPM reference.
+ *
+ * Note that we cowardly refuse queuing work after musb PM runtime
+ * resume is done calling musb_run_resume_work() and return -EINPROGRESS
+ * instead.
+ */
+int musb_queue_resume_work(struct musb *musb,
+                          int (*callback)(struct musb *musb, void *data),
+                          void *data)
+{
+       struct musb_pending_work *w;
+       unsigned long flags;
+       int error;
+
+       if (WARN_ON(!callback))
+               return -EINVAL;
+
+       if (pm_runtime_active(musb->controller))
+               return callback(musb, data);
+
+       w = devm_kzalloc(musb->controller, sizeof(*w), GFP_ATOMIC);
+       if (!w)
+               return -ENOMEM;
+
+       w->callback = callback;
+       w->data = data;
+       spin_lock_irqsave(&musb->list_lock, flags);
+       if (musb->is_runtime_suspended) {
+               list_add_tail(&w->node, &musb->pending_list);
+               error = 0;
+       } else {
+               dev_err(musb->controller, "could not add resume work %p\n",
+                       callback);
+               devm_kfree(musb->controller, w);
+               error = -EINPROGRESS;
+       }
+       spin_unlock_irqrestore(&musb->list_lock, flags);
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(musb_queue_resume_work);
+
 static void musb_deassert_reset(struct work_struct *work)
 {
        struct musb *musb;
@@ -2065,6 +2153,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        }
 
        spin_lock_init(&musb->lock);
+       spin_lock_init(&musb->list_lock);
        musb->board_set_power = plat->set_power;
        musb->min_power = plat->min_power;
        musb->ops = plat->platform_ops;
@@ -2114,11 +2203,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                musb->io.ep_offset = musb_flat_ep_offset;
                musb->io.ep_select = musb_flat_ep_select;
        }
-       /* And override them with platform specific ops if specified. */
-       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;
 
        /* At least tusb6010 has its own offsets */
        if (musb->ops->ep_offset)
@@ -2213,7 +2297,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        musb_generic_disable(musb);
 
        /* Init IRQ workqueue before request_irq */
-       INIT_WORK(&musb->irq_work, musb_irq_work);
+       INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work);
        INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
        INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume);
 
@@ -2296,6 +2380,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        if (status)
                goto fail5;
 
+       musb->is_initialized = 1;
        pm_runtime_mark_last_busy(musb->controller);
        pm_runtime_put_autosuspend(musb->controller);
 
@@ -2309,7 +2394,7 @@ fail4:
        musb_host_cleanup(musb);
 
 fail3:
-       cancel_work_sync(&musb->irq_work);
+       cancel_delayed_work_sync(&musb->irq_work);
        cancel_delayed_work_sync(&musb->finish_resume_work);
        cancel_delayed_work_sync(&musb->deassert_reset_work);
        if (musb->dma_controller)
@@ -2376,7 +2461,7 @@ static int musb_remove(struct platform_device *pdev)
         */
        musb_exit_debugfs(musb);
 
-       cancel_work_sync(&musb->irq_work);
+       cancel_delayed_work_sync(&musb->irq_work);
        cancel_delayed_work_sync(&musb->finish_resume_work);
        cancel_delayed_work_sync(&musb->deassert_reset_work);
        pm_runtime_get_sync(musb->controller);
@@ -2562,6 +2647,7 @@ static int musb_suspend(struct device *dev)
 
        musb_platform_disable(musb);
        musb_generic_disable(musb);
+       WARN_ON(!list_empty(&musb->pending_list));
 
        spin_lock_irqsave(&musb->lock, flags);
 
@@ -2583,9 +2669,11 @@ static int musb_suspend(struct device *dev)
 
 static int musb_resume(struct device *dev)
 {
-       struct musb     *musb = dev_to_musb(dev);
-       u8              devctl;
-       u8              mask;
+       struct musb *musb = dev_to_musb(dev);
+       unsigned long flags;
+       int error;
+       u8 devctl;
+       u8 mask;
 
        /*
         * For static cmos like DaVinci, register values were preserved
@@ -2619,6 +2707,13 @@ static int musb_resume(struct device *dev)
 
        musb_start(musb);
 
+       spin_lock_irqsave(&musb->lock, flags);
+       error = musb_run_resume_work(musb);
+       if (error)
+               dev_err(musb->controller, "resume work failed with %i\n",
+                       error);
+       spin_unlock_irqrestore(&musb->lock, flags);
+
        return 0;
 }
 
@@ -2627,14 +2722,16 @@ static int musb_runtime_suspend(struct device *dev)
        struct musb     *musb = dev_to_musb(dev);
 
        musb_save_context(musb);
+       musb->is_runtime_suspended = 1;
 
        return 0;
 }
 
 static int musb_runtime_resume(struct device *dev)
 {
-       struct musb     *musb = dev_to_musb(dev);
-       static int      first = 1;
+       struct musb *musb = dev_to_musb(dev);
+       unsigned long flags;
+       int error;
 
        /*
         * When pm_runtime_get_sync called for the first time in driver
@@ -2645,9 +2742,10 @@ static int musb_runtime_resume(struct device *dev)
         * Also context restore without save does not make
         * any sense
         */
-       if (!first)
-               musb_restore_context(musb);
-       first = 0;
+       if (!musb->is_initialized)
+               return 0;
+
+       musb_restore_context(musb);
 
        if (musb->need_finish_resume) {
                musb->need_finish_resume = 0;
@@ -2655,6 +2753,14 @@ static int musb_runtime_resume(struct device *dev)
                                msecs_to_jiffies(USB_RESUME_TIMEOUT));
        }
 
+       spin_lock_irqsave(&musb->lock, flags);
+       error = musb_run_resume_work(musb);
+       if (error)
+               dev_err(musb->controller, "resume work failed with %i\n",
+                       error);
+       musb->is_runtime_suspended = 0;
+       spin_unlock_irqrestore(&musb->lock, flags);
+
        return 0;
 }
 
index 2cb88a498f8a5681265654e079456e0ae944667e..91817d77d59c8ecd226e25fb6ce9e07b5a597d3f 100644 (file)
@@ -303,13 +303,14 @@ struct musb_context_registers {
 struct musb {
        /* device lock */
        spinlock_t              lock;
+       spinlock_t              list_lock;      /* resume work list lock */
 
        struct musb_io          io;
        const struct musb_platform_ops *ops;
        struct musb_context_registers context;
 
        irqreturn_t             (*isr)(int, void *);
-       struct work_struct      irq_work;
+       struct delayed_work     irq_work;
        struct delayed_work     deassert_reset_work;
        struct delayed_work     finish_resume_work;
        struct delayed_work     gadget_work;
@@ -337,6 +338,7 @@ struct musb {
        struct list_head        control;        /* of musb_qh */
        struct list_head        in_bulk;        /* of musb_qh */
        struct list_head        out_bulk;       /* of musb_qh */
+       struct list_head        pending_list;   /* pending work list */
 
        struct timer_list       otg_timer;
        struct notifier_block   nb;
@@ -379,12 +381,15 @@ struct musb {
 
        int                     port_mode;      /* MUSB_PORT_MODE_* */
        bool                    session;
-       bool                    quirk_invalid_vbus;
+       unsigned long           quirk_retries;
        bool                    is_host;
 
        int                     a_wait_bcon;    /* VBUS timeout in msecs */
        unsigned long           idle_timeout;   /* Next timeout in jiffies */
 
+       unsigned                is_initialized:1;
+       unsigned                is_runtime_suspended:1;
+
        /* active means connected and not suspended */
        unsigned                is_active:1;
 
@@ -540,6 +545,10 @@ extern irqreturn_t musb_interrupt(struct musb *);
 
 extern void musb_hnp_stop(struct musb *musb);
 
+int musb_queue_resume_work(struct musb *musb,
+                          int (*callback)(struct musb *musb, void *data),
+                          void *data);
+
 static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
 {
        if (musb->ops->set_vbus)
index 0f17d2140db6e5c36eceef43b185d2c7c183e091..feae1561b9abb6924d2fe2fc6f1222dfac9d2be7 100644 (file)
@@ -185,24 +185,19 @@ static void dsps_musb_disable(struct musb *musb)
        musb_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
        musb_writel(reg_base, wrp->epintr_clear,
                         wrp->txep_bitmap | wrp->rxep_bitmap);
+       del_timer_sync(&glue->timer);
        musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
 }
 
-static void otg_timer(unsigned long _musb)
+/* Caller must take musb->lock */
+static int dsps_check_status(struct musb *musb, void *unused)
 {
-       struct musb *musb = (void *)_musb;
        void __iomem *mregs = musb->mregs;
        struct device *dev = musb->controller;
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
        u8 devctl;
-       unsigned long flags;
        int skip_session = 0;
-       int err;
-
-       err = pm_runtime_get_sync(dev);
-       if (err < 0)
-               dev_err(dev, "Poll could not pm_runtime_get: %i\n", err);
 
        /*
         * We poll because DSPS IP's won't expose several OTG-critical
@@ -212,7 +207,6 @@ static void otg_timer(unsigned long _musb)
        dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
                                usb_otg_state_string(musb->xceiv->otg->state));
 
-       spin_lock_irqsave(&musb->lock, flags);
        switch (musb->xceiv->otg->state) {
        case OTG_STATE_A_WAIT_VRISE:
                mod_timer(&glue->timer, jiffies +
@@ -245,8 +239,30 @@ static void otg_timer(unsigned long _musb)
        default:
                break;
        }
-       spin_unlock_irqrestore(&musb->lock, flags);
 
+       return 0;
+}
+
+static void otg_timer(unsigned long _musb)
+{
+       struct musb *musb = (void *)_musb;
+       struct device *dev = musb->controller;
+       unsigned long flags;
+       int err;
+
+       err = pm_runtime_get(dev);
+       if ((err != -EINPROGRESS) && err < 0) {
+               dev_err(dev, "Poll could not pm_runtime_get: %i\n", err);
+               pm_runtime_put_noidle(dev);
+
+               return;
+       }
+
+       spin_lock_irqsave(&musb->lock, flags);
+       err = musb_queue_resume_work(musb, dsps_check_status, NULL);
+       if (err < 0)
+               dev_err(dev, "%s resume work: %i\n", __func__, err);
+       spin_unlock_irqrestore(&musb->lock, flags);
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
 }
@@ -767,28 +783,13 @@ static int dsps_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, glue);
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_use_autosuspend(&pdev->dev);
-       pm_runtime_set_autosuspend_delay(&pdev->dev, 200);
-
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
-               goto err2;
-       }
-
        ret = dsps_create_musb_pdev(glue, pdev);
        if (ret)
-               goto err3;
-
-       pm_runtime_mark_last_busy(&pdev->dev);
-       pm_runtime_put_autosuspend(&pdev->dev);
+               goto err;
 
        return 0;
 
-err3:
-       pm_runtime_put_sync(&pdev->dev);
-err2:
-       pm_runtime_dont_use_autosuspend(&pdev->dev);
+err:
        pm_runtime_disable(&pdev->dev);
        return ret;
 }
@@ -799,9 +800,6 @@ static int dsps_remove(struct platform_device *pdev)
 
        platform_device_unregister(glue->musb);
 
-       /* disable usbss clocks */
-       pm_runtime_dont_use_autosuspend(&pdev->dev);
-       pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
index bff4869a57cd193072215662e984e367eb551cdb..a55173c9e5645d6f5245c0ff78c4ccf151d75107 100644 (file)
@@ -1114,7 +1114,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
                        musb_ep->dma ? "dma, " : "",
                        musb_ep->packet_sz);
 
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
 
 fail:
        spin_unlock_irqrestore(&musb->lock, flags);
@@ -1158,7 +1158,7 @@ static int musb_gadget_disable(struct usb_ep *ep)
        musb_ep->desc = NULL;
        musb_ep->end_point.desc = NULL;
 
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
 
        spin_unlock_irqrestore(&(musb->lock), flags);
 
@@ -1222,13 +1222,22 @@ void musb_ep_restart(struct musb *musb, struct musb_request *req)
                rxstate(musb, req);
 }
 
+static int musb_ep_restart_resume_work(struct musb *musb, void *data)
+{
+       struct musb_request *req = data;
+
+       musb_ep_restart(musb, req);
+
+       return 0;
+}
+
 static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
                        gfp_t gfp_flags)
 {
        struct musb_ep          *musb_ep;
        struct musb_request     *request;
        struct musb             *musb;
-       int                     status = 0;
+       int                     status;
        unsigned long           lockflags;
 
        if (!ep || !req)
@@ -1245,6 +1254,17 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
        if (request->ep != musb_ep)
                return -EINVAL;
 
+       status = pm_runtime_get(musb->controller);
+       if ((status != -EINPROGRESS) && status < 0) {
+               dev_err(musb->controller,
+                       "pm runtime get failed in %s\n",
+                       __func__);
+               pm_runtime_put_noidle(musb->controller);
+
+               return status;
+       }
+       status = 0;
+
        trace_musb_req_enq(request);
 
        /* request is mine now... */
@@ -1270,11 +1290,20 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
        list_add_tail(&request->list, &musb_ep->req_list);
 
        /* it this is the head of the queue, start i/o ... */
-       if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
-               musb_ep_restart(musb, request);
+       if (!musb_ep->busy && &request->list == musb_ep->req_list.next) {
+               status = musb_queue_resume_work(musb,
+                                               musb_ep_restart_resume_work,
+                                               request);
+               if (status < 0)
+                       dev_err(musb->controller, "%s resume work: %i\n",
+                               __func__, status);
+       }
 
 unlock:
        spin_unlock_irqrestore(&musb->lock, lockflags);
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
+
        return status;
 }
 
@@ -1965,7 +1994,7 @@ static int musb_gadget_stop(struct usb_gadget *g)
         */
 
        /* Force check of devctl register for PM runtime */
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
 
        pm_runtime_mark_last_busy(musb->controller);
        pm_runtime_put_autosuspend(musb->controller);
index 1ab6973d4f6197083e766f70db455c4c7c8bd8e2..e8be8e39ab8fbd2d5b03a6fdc98dc3d78b00512e 100644 (file)
@@ -287,6 +287,7 @@ static int omap2430_musb_init(struct musb *musb)
        }
        musb->isr = omap2430_musb_interrupt;
        phy_init(musb->phy);
+       phy_power_on(musb->phy);
 
        l = musb_readl(musb->mregs, OTG_INTERFSEL);
 
@@ -323,8 +324,6 @@ static void omap2430_musb_enable(struct musb *musb)
        struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
        struct omap_musb_board_data *data = pdata->board_data;
 
-       if (!WARN_ON(!musb->phy))
-               phy_power_on(musb->phy);
 
        switch (glue->status) {
 
@@ -361,9 +360,6 @@ static void omap2430_musb_disable(struct musb *musb)
        struct device *dev = musb->controller;
        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 
-       if (!WARN_ON(!musb->phy))
-               phy_power_off(musb->phy);
-
        if (glue->status != MUSB_UNKNOWN)
                omap_control_usb_set_mode(glue->control_otghs,
                        USB_MODE_DISCONNECT);
@@ -375,6 +371,7 @@ static int omap2430_musb_exit(struct musb *musb)
        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 
        omap2430_low_level_exit(musb);
+       phy_power_off(musb->phy);
        phy_exit(musb->phy);
        musb->phy = NULL;
        cancel_work_sync(&glue->omap_musb_mailbox_work);
@@ -516,17 +513,18 @@ static int omap2430_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(glue->dev);
-       pm_runtime_use_autosuspend(glue->dev);
-       pm_runtime_set_autosuspend_delay(glue->dev, 100);
 
        ret = platform_device_add(musb);
        if (ret) {
                dev_err(&pdev->dev, "failed to register musb device\n");
-               goto err2;
+               goto err3;
        }
 
        return 0;
 
+err3:
+       pm_runtime_disable(glue->dev);
+
 err2:
        platform_device_put(musb);
 
@@ -538,10 +536,7 @@ static int omap2430_remove(struct platform_device *pdev)
 {
        struct omap2430_glue *glue = platform_get_drvdata(pdev);
 
-       pm_runtime_get_sync(glue->dev);
        platform_device_unregister(glue->musb);
-       pm_runtime_put_sync(glue->dev);
-       pm_runtime_dont_use_autosuspend(glue->dev);
        pm_runtime_disable(glue->dev);
 
        return 0;
index df7c9f46be548f61800b7beaa7f182b5dc447ad5..e85cc8e4e7a9c02e32fdef579d04d8adb22469df 100644 (file)
@@ -724,7 +724,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
                        dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
                                usb_otg_state_string(musb->xceiv->otg->state), otg_stat);
                        idle_timeout = jiffies + (1 * HZ);
-                       schedule_work(&musb->irq_work);
+                       schedule_delayed_work(&musb->irq_work, 0);
 
                } else /* A-dev state machine */ {
                        dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
@@ -814,7 +814,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
                        break;
                }
        }
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
 
        return idle_timeout;
 }
@@ -864,7 +864,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)
                musb_writel(tbase, TUSB_PRCM_WAKEUP_CLEAR, reg);
                if (reg & ~TUSB_PRCM_WNORCS) {
                        musb->is_active = 1;
-                       schedule_work(&musb->irq_work);
+                       schedule_delayed_work(&musb->irq_work, 0);
                }
                dev_dbg(musb->controller, "wake %sactive %02x\n",
                                musb->is_active ? "" : "in", reg);
index 1d70add926f0ff632964ca92fc92a3f2f035fb7b..d544b331c9f2ce80d83095f30184e2102eda6ea6 100644 (file)
@@ -9,6 +9,7 @@
  *
  */
 
+#include <linux/delay.h>
 #include <linux/io.h>
 #include "common.h"
 #include "rcar3.h"
@@ -35,10 +36,13 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
 
        usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG);
 
-       if (enable)
+       if (enable) {
                usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
-       else
+               /* The controller on R-Car Gen3 needs to wait up to 45 usec */
+               udelay(45);
+       } else {
                usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
+       }
 
        return 0;
 }
index 54a4de0efdbaa48fa7e1a49672e114657737b42d..243ac5ebe46a02560d5cbe3ca8fd97fe4e5eb721 100644 (file)
@@ -131,6 +131,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
+       { USB_DEVICE(0x10C4, 0x8962) }, /* Brim Brothers charging dock */
        { 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 */
@@ -1077,7 +1078,9 @@ static int cp210x_tiocmget(struct tty_struct *tty)
        u8 control;
        int result;
 
-       cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control);
+       result = cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control);
+       if (result)
+               return result;
 
        result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
                |((control & CONTROL_RTS) ? TIOCM_RTS : 0)
index b2d767e743fc2258c8b13e84401e5f34b60efcec..6e9fc8bcc285d122c2148cefcb7c8f57ae6c4aa2 100644 (file)
@@ -986,7 +986,8 @@ static const struct usb_device_id id_table_combined[] = {
        /* ekey Devices */
        { USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) },
        /* Infineon Devices */
-       { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },
+       { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC1798_PID, 1) },
+       { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC2X7_PID, 1) },
        /* GE Healthcare devices */
        { USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
        /* Active Research (Actisense) devices */
@@ -1011,6 +1012,8 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7563U_PID) },
        { USB_DEVICE(WICED_VID, WICED_USB20706V2_PID) },
+       { USB_DEVICE(TI_VID, TI_CC3200_LAUNCHPAD_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { }                                     /* Terminating entry */
 };
 
index f87a938cf00571eb69edbd8d625f58041384d5fa..48ee04c94a7541ad6c5f9023be107246207c56fd 100644 (file)
 #define ATMEL_VID              0x03eb /* Vendor ID */
 #define STK541_PID             0x2109 /* Zigbee Controller */
 
+/*
+ * Texas Instruments
+ */
+#define TI_VID                 0x0451
+#define TI_CC3200_LAUNCHPAD_PID        0xC32A /* SimpleLink Wi-Fi CC3200 LaunchPad */
+
 /*
  * Blackfin gnICE JTAG
  * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice
 /*
  * Infineon Technologies
  */
-#define INFINEON_VID           0x058b
-#define INFINEON_TRIBOARD_PID  0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */
+#define INFINEON_VID                   0x058b
+#define INFINEON_TRIBOARD_TC1798_PID   0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */
+#define INFINEON_TRIBOARD_TC2X7_PID    0x0043 /* DAS JTAG TriBoard TC2X7 V1.0 */
 
 /*
  * Acton Research Corp.
index d213cf44a7e45ef8ae692bf4a9e63d31088cae8b..4a037b4a79cf3168cb45d60d1b6488ac21681570 100644 (file)
@@ -1078,7 +1078,8 @@ static int usb_serial_probe(struct usb_interface *interface,
 
        serial->disconnected = 0;
 
-       usb_serial_console_init(serial->port[0]->minor);
+       if (num_ports > 0)
+               usb_serial_console_init(serial->port[0]->minor);
 exit:
        module_put(type->driver.owner);
        return 0;
index ffd086733421316bed0d3c0cf56aa20134fb54f5..1a59f335b063e7e79f8ece2173f2f03574ce3a5b 100644 (file)
@@ -954,10 +954,15 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
 
        /* COMMAND STAGE */
        /* let's send the command via the control pipe */
+       /*
+        * Command is sometime (f.e. after scsi_eh_prep_cmnd) on the stack.
+        * Stack may be vmallocated.  So no DMA for us.  Make a copy.
+        */
+       memcpy(us->iobuf, srb->cmnd, srb->cmd_len);
        result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
                                      US_CBI_ADSC, 
                                      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
-                                     us->ifnum, srb->cmnd, srb->cmd_len);
+                                     us->ifnum, us->iobuf, srb->cmd_len);
 
        /* check the return code for the command */
        usb_stor_dbg(us, "Call to usb_stor_ctrl_transfer() returned %d\n",
index 79b2b628066d81c5e5c6ceda10f707587c55b1c8..79451f7ef1b76301cc881379ad28ce12e4b4dc33 100644 (file)
@@ -133,6 +133,13 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
                bo[itr] = bi1[itr] ^ bi2[itr];
 }
 
+/* Scratch space for MAC calculations. */
+struct wusb_mac_scratch {
+       struct aes_ccm_b0 b0;
+       struct aes_ccm_b1 b1;
+       struct aes_ccm_a ax;
+};
+
 /*
  * CC-MAC function WUSB1.0[6.5]
  *
@@ -197,16 +204,15 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2,
  *       what sg[4] is for. Maybe there is a smarter way to do this.
  */
 static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
-                       struct crypto_cipher *tfm_aes, void *mic,
+                       struct crypto_cipher *tfm_aes,
+                       struct wusb_mac_scratch *scratch,
+                       void *mic,
                        const struct aes_ccm_nonce *n,
                        const struct aes_ccm_label *a, const void *b,
                        size_t blen)
 {
        int result = 0;
        SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc);
-       struct aes_ccm_b0 b0;
-       struct aes_ccm_b1 b1;
-       struct aes_ccm_a ax;
        struct scatterlist sg[4], sg_dst;
        void *dst_buf;
        size_t dst_size;
@@ -218,16 +224,17 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
         * These checks should be compile time optimized out
         * ensure @a fills b1's mac_header and following fields
         */
-       WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la));
-       WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block));
-       WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block));
-       WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block));
+       WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
+       WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
+       WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
+       WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
 
        result = -ENOMEM;
        zero_padding = blen % sizeof(struct aes_ccm_block);
        if (zero_padding)
                zero_padding = sizeof(struct aes_ccm_block) - zero_padding;
-       dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding;
+       dst_size = blen + sizeof(scratch->b0) + sizeof(scratch->b1) +
+               zero_padding;
        dst_buf = kzalloc(dst_size, GFP_KERNEL);
        if (!dst_buf)
                goto error_dst_buf;
@@ -235,9 +242,9 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
        memset(iv, 0, sizeof(iv));
 
        /* Setup B0 */
-       b0.flags = 0x59;        /* Format B0 */
-       b0.ccm_nonce = *n;
-       b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */
+       scratch->b0.flags = 0x59;       /* Format B0 */
+       scratch->b0.ccm_nonce = *n;
+       scratch->b0.lm = cpu_to_be16(0);        /* WUSB1.0[6.5] sez l(m) is 0 */
 
        /* Setup B1
         *
@@ -246,12 +253,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
         * 14'--after clarification, it means to use A's contents
         * for MAC Header, EO, sec reserved and padding.
         */
-       b1.la = cpu_to_be16(blen + 14);
-       memcpy(&b1.mac_header, a, sizeof(*a));
+       scratch->b1.la = cpu_to_be16(blen + 14);
+       memcpy(&scratch->b1.mac_header, a, sizeof(*a));
 
        sg_init_table(sg, ARRAY_SIZE(sg));
-       sg_set_buf(&sg[0], &b0, sizeof(b0));
-       sg_set_buf(&sg[1], &b1, sizeof(b1));
+       sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0));
+       sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
        sg_set_buf(&sg[2], b, blen);
        /* 0 if well behaved :) */
        sg_set_buf(&sg[3], bzero, zero_padding);
@@ -276,11 +283,12 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
         * POS Crypto API: size is assumed to be AES's block size.
         * Thanks for documenting it -- tip taken from airo.c
         */
-       ax.flags = 0x01;                /* as per WUSB 1.0 spec */
-       ax.ccm_nonce = *n;
-       ax.counter = 0;
-       crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax);
-       bytewise_xor(mic, &ax, iv, 8);
+       scratch->ax.flags = 0x01;               /* as per WUSB 1.0 spec */
+       scratch->ax.ccm_nonce = *n;
+       scratch->ax.counter = 0;
+       crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax,
+                                 (void *)&scratch->ax);
+       bytewise_xor(mic, &scratch->ax, iv, 8);
        result = 8;
 error_cbc_crypt:
        kfree(dst_buf);
@@ -303,6 +311,7 @@ ssize_t wusb_prf(void *out, size_t out_size,
        struct aes_ccm_nonce n = *_n;
        struct crypto_skcipher *tfm_cbc;
        struct crypto_cipher *tfm_aes;
+       struct wusb_mac_scratch *scratch;
        u64 sfn = 0;
        __le64 sfn_le;
 
@@ -329,17 +338,25 @@ ssize_t wusb_prf(void *out, size_t out_size,
                printk(KERN_ERR "E: can't set AES key: %d\n", (int)result);
                goto error_setkey_aes;
        }
+       scratch = kmalloc(sizeof(*scratch), GFP_KERNEL);
+       if (!scratch) {
+               result = -ENOMEM;
+               goto error_alloc_scratch;
+       }
 
        for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
                sfn_le = cpu_to_le64(sfn++);
                memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
-               result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes,
+               result = wusb_ccm_mac(tfm_cbc, tfm_aes, scratch, out + bytes,
                                      &n, a, b, blen);
                if (result < 0)
                        goto error_ccm_mac;
                bytes += result;
        }
        result = bytes;
+
+       kfree(scratch);
+error_alloc_scratch:
 error_ccm_mac:
 error_setkey_aes:
        crypto_free_cipher(tfm_aes);
index d059ad4d0dbdc76f8fbbdbfc47dfd990d2006fc5..97ee1b46db698f03dee8ea50beb00e864bff0579 100644 (file)
@@ -56,8 +56,11 @@ static struct uwb_rc *uwb_rc_find_by_index(int index)
        struct uwb_rc *rc = NULL;
 
        dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
-       if (dev)
+       if (dev) {
                rc = dev_get_drvdata(dev);
+               put_device(dev);
+       }
+
        return rc;
 }
 
@@ -467,7 +470,9 @@ struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc)
        if (dev) {
                rc = dev_get_drvdata(dev);
                __uwb_rc_get(rc);
+               put_device(dev);
        }
+
        return rc;
 }
 EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
@@ -520,8 +525,11 @@ struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
 
        dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
                                find_rc_grandpa);
-       if (dev)
+       if (dev) {
                rc = dev_get_drvdata(dev);
+               put_device(dev);
+       }
+
        return rc;
 }
 EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
@@ -553,8 +561,10 @@ struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
        struct uwb_rc *rc = NULL;
 
        dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
-       if (dev)
+       if (dev) {
                rc = dev_get_drvdata(dev);
+               put_device(dev);
+       }
 
        return rc;
 }
index c1304b8d498530124c7ca30319c12cc823e84d6e..678e93741ae156bf5d2c41b7a52f7b215262210d 100644 (file)
@@ -97,6 +97,8 @@ static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
 
        dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc);
 
+       put_device(dev);
+
        return (dev != NULL);
 }
 
index d624a527777f6a12d5f63e273008908fbf0cacfc..031bc08d000d4a7d774f3793df7be5168712e161 100644 (file)
@@ -829,8 +829,9 @@ static long vfio_pci_ioctl(void *device_data,
 
        } else if (cmd == VFIO_DEVICE_SET_IRQS) {
                struct vfio_irq_set hdr;
+               size_t size;
                u8 *data = NULL;
-               int ret = 0;
+               int max, ret = 0;
 
                minsz = offsetofend(struct vfio_irq_set, count);
 
@@ -838,23 +839,31 @@ static long vfio_pci_ioctl(void *device_data,
                        return -EFAULT;
 
                if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS ||
+                   hdr.count >= (U32_MAX - hdr.start) ||
                    hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
                                  VFIO_IRQ_SET_ACTION_TYPE_MASK))
                        return -EINVAL;
 
-               if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
-                       size_t size;
-                       int max = vfio_pci_get_irq_count(vdev, hdr.index);
+               max = vfio_pci_get_irq_count(vdev, hdr.index);
+               if (hdr.start >= max || hdr.start + hdr.count > max)
+                       return -EINVAL;
 
-                       if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
-                               size = sizeof(uint8_t);
-                       else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
-                               size = sizeof(int32_t);
-                       else
-                               return -EINVAL;
+               switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
+               case VFIO_IRQ_SET_DATA_NONE:
+                       size = 0;
+                       break;
+               case VFIO_IRQ_SET_DATA_BOOL:
+                       size = sizeof(uint8_t);
+                       break;
+               case VFIO_IRQ_SET_DATA_EVENTFD:
+                       size = sizeof(int32_t);
+                       break;
+               default:
+                       return -EINVAL;
+               }
 
-                       if (hdr.argsz - minsz < hdr.count * size ||
-                           hdr.start >= max || hdr.start + hdr.count > max)
+               if (size) {
+                       if (hdr.argsz - minsz < hdr.count * size)
                                return -EINVAL;
 
                        data = memdup_user((void __user *)(arg + minsz),
index c2e60893cd09a5772d608ffa5e3364c288f205ab..1c46045b0e7fc6b2e8ef421853742851aa880d7e 100644 (file)
@@ -256,7 +256,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
        if (!is_irq_none(vdev))
                return -EINVAL;
 
-       vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+       vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
        if (!vdev->ctx)
                return -ENOMEM;
 
index e3b30ea9ece5945c935791798ab27ed8f6c3dd11..a504e2e003da58181e6fbf4e8276c8f4615e18f2 100644 (file)
@@ -506,7 +506,7 @@ static void vhost_vsock_reset_orphans(struct sock *sk)
         * executing.
         */
 
-       if (!vhost_vsock_get(vsk->local_addr.svm_cid)) {
+       if (!vhost_vsock_get(vsk->remote_addr.svm_cid)) {
                sock_set_flag(sk, SOCK_DONE);
                vsk->peer_shutdown = SHUTDOWN_MASK;
                sk->sk_state = SS_UNCONNECTED;
index 19ad8645d93cd25a9f41375bcb30a1677ae721b7..e5d9bfc1703a5ff9fcaafe44fbb3c7e152fa16c7 100644 (file)
@@ -526,8 +526,8 @@ int versatile_clcd_init_panel(struct clcd_fb *fb,
        np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
                                             &clcd_id);
        if (!np) {
-               dev_err(dev, "no Versatile syscon node\n");
-               return -ENODEV;
+               /* Vexpress does not have this */
+               return 0;
        }
        versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
 
index 3b1ca441107370d39c54bd4bffa24248eaa730c5..a2564ab91e62d3c2775441d292e54e1d25492a40 100644 (file)
@@ -686,8 +686,8 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
        if (!pages)
                return -ENOMEM;
 
-       ret = get_user_pages_unlocked((unsigned long)buf, nr_pages, WRITE,
-                       0, pages);
+       ret = get_user_pages_unlocked((unsigned long)buf, nr_pages, pages,
+                       FOLL_WRITE);
 
        if (ret < nr_pages) {
                nr_pages = ret;
index 60bdad3a689b8280b373164f7a13fdcb2a5a1cc2..150ce2abf6c8f193b4e3b5c9fa66001cd709f39e 100644 (file)
@@ -245,8 +245,8 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
        /* Get the physical addresses of the source buffer */
        down_read(&current->mm->mmap_sem);
        num_pinned = get_user_pages(param.local_vaddr - lb_offset,
-               num_pages, (param.source == -1) ? READ : WRITE,
-               0, pages, NULL);
+               num_pages, (param.source == -1) ? 0 : FOLL_WRITE,
+               pages, NULL);
        up_read(&current->mm->mmap_sem);
 
        if (num_pinned != num_pages) {
diff --git a/drivers/virtio/config.c b/drivers/virtio/config.c
deleted file mode 100644 (file)
index f70bcd2..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Configuration space parsing helpers for virtio.
- *
- * The configuration is [type][len][... len bytes ...] fields.
- *
- * Copyright 2007 Rusty Russell, IBM Corporation.
- * GPL v2 or later.
- */
-#include <linux/err.h>
-#include <linux/virtio.h>
-#include <linux/virtio_config.h>
-#include <linux/bug.h>
-
index 4e7003db12c4a4385034231d23cd1318006eca04..181793f078524ae8c06751d4b03677a132b4a7c3 100644 (file)
@@ -577,6 +577,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
 
        virtio_device_ready(vdev);
 
+       if (towards_target(vb))
+               virtballoon_changed(vdev);
        return 0;
 
 out_del_vqs:
index 8c4e61783441b9f818c18b6dedd0b113b575ab77..6d9e5173d5fa6b7f4da58b48268dd48c7e8c1e1f 100644 (file)
@@ -212,10 +212,18 @@ int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev)
                return -ENODEV;
        }
 
-       rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(64));
-       if (rc)
-               rc = dma_set_mask_and_coherent(&pci_dev->dev,
-                                               DMA_BIT_MASK(32));
+       rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64));
+       if (rc) {
+               rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32));
+       } else {
+               /*
+                * The virtio ring base address is expressed as a 32-bit PFN,
+                * with a page size of 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT.
+                */
+               dma_set_coherent_mask(&pci_dev->dev,
+                               DMA_BIT_MASK(32 + VIRTIO_PCI_QUEUE_ADDR_SHIFT));
+       }
+
        if (rc)
                dev_warn(&pci_dev->dev, "Failed to enable 64-bit or 32-bit DMA.  Trying to continue, but this might not work.\n");
 
index ed9c9eeedfe5f83fd1b7b3ca475280643d8758f1..489bfc61cf30001626307f4e2f936d2e65cdeb73 100644 (file)
@@ -167,7 +167,7 @@ static bool vring_use_dma_api(struct virtio_device *vdev)
  * making all of the arch DMA ops work on the vring device itself
  * is a mess.  For now, we use the parent device for DMA ops.
  */
-static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
+static inline struct device *vring_dma_dev(const struct vring_virtqueue *vq)
 {
        return vq->vq.vdev->dev.parent;
 }
@@ -732,7 +732,8 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
 
        if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
                vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
-               vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+               if (!vq->event)
+                       vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
        }
 
 }
@@ -764,7 +765,8 @@ unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq)
         * entry. Always do both to keep code simple. */
        if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
                vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
-               vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+               if (!vq->event)
+                       vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
        }
        vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx);
        END_USE(vq);
@@ -832,10 +834,11 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
         * more to do. */
        /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to
         * either clear the flags bit or point the event index at the next
-        * entry. Always do both to keep code simple. */
+        * entry. Always update the event index to keep code simple. */
        if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
                vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
-               vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+               if (!vq->event)
+                       vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
        }
        /* TODO: tune this threshold */
        bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4;
@@ -953,7 +956,8 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
        /* No callback?  Tell other side not to bother us. */
        if (!callback) {
                vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
-               vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow);
+               if (!vq->event)
+                       vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow);
        }
 
        /* Put everything in free lists. */
index 15b64076bc26257abffd02a60de7b2fe4b22c4e0..bdbadaa47ef3ecb481b200785d4bc1aa9981f6e4 100644 (file)
@@ -156,12 +156,16 @@ size_t vme_get_size(struct vme_resource *resource)
        case VME_MASTER:
                retval = vme_master_get(resource, &enabled, &base, &size,
                        &aspace, &cycle, &dwidth);
+               if (retval)
+                       return 0;
 
                return size;
                break;
        case VME_SLAVE:
                retval = vme_slave_get(resource, &enabled, &base, &size,
                        &buf_base, &aspace, &cycle);
+               if (retval)
+                       return 0;
 
                return size;
                break;
index fdd3228e06781c4dd150091673e51ba3bdb9ce71..3eb58cb51e5648f87f5d732e33cde8c6cd49569d 100644 (file)
@@ -155,6 +155,7 @@ config TANGOX_WATCHDOG
 config WDAT_WDT
        tristate "ACPI Watchdog Action Table (WDAT)"
        depends on ACPI
+       select WATCHDOG_CORE
        select ACPI_WATCHDOG
        help
          This driver adds support for systems with ACPI Watchdog Action
index e473e3b237203fcc7440128e804e3bbb141fc0b2..6d1fbda0f461ca2d2304eaeb43aef35adfd77cf4 100644 (file)
@@ -499,6 +499,10 @@ static int wdat_wdt_resume_noirq(struct device *dev)
                ret = wdat_wdt_enable_reboot(wdat);
                if (ret)
                        return ret;
+
+               ret = wdat_wdt_ping(&wdat->wdd);
+               if (ret)
+                       return ret;
        }
 
        return wdat_wdt_start(&wdat->wdd);
index e12bd3635f832e7fa5330667fe77f32fe305db4b..26e5e8507f031f3118229f5164286160d3bcece6 100644 (file)
@@ -168,7 +168,9 @@ out:
 #endif /* CONFIG_HIBERNATE_CALLBACKS */
 
 struct shutdown_handler {
-       const char *command;
+#define SHUTDOWN_CMD_SIZE 11
+       const char command[SHUTDOWN_CMD_SIZE];
+       bool flag;
        void (*cb)(void);
 };
 
@@ -206,22 +208,22 @@ static void do_reboot(void)
        ctrl_alt_del();
 }
 
+static struct shutdown_handler shutdown_handlers[] = {
+       { "poweroff",   true,   do_poweroff },
+       { "halt",       false,  do_poweroff },
+       { "reboot",     true,   do_reboot   },
+#ifdef CONFIG_HIBERNATE_CALLBACKS
+       { "suspend",    true,   do_suspend  },
+#endif
+};
+
 static void shutdown_handler(struct xenbus_watch *watch,
                             const char **vec, unsigned int len)
 {
        char *str;
        struct xenbus_transaction xbt;
        int err;
-       static struct shutdown_handler handlers[] = {
-               { "poweroff",   do_poweroff },
-               { "halt",       do_poweroff },
-               { "reboot",     do_reboot   },
-#ifdef CONFIG_HIBERNATE_CALLBACKS
-               { "suspend",    do_suspend  },
-#endif
-               {NULL, NULL},
-       };
-       static struct shutdown_handler *handler;
+       int idx;
 
        if (shutting_down != SHUTDOWN_INVALID)
                return;
@@ -238,13 +240,13 @@ static void shutdown_handler(struct xenbus_watch *watch,
                return;
        }
 
-       for (handler = &handlers[0]; handler->command; handler++) {
-               if (strcmp(str, handler->command) == 0)
+       for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) {
+               if (strcmp(str, shutdown_handlers[idx].command) == 0)
                        break;
        }
 
        /* Only acknowledge commands which we are prepared to handle. */
-       if (handler->cb)
+       if (idx < ARRAY_SIZE(shutdown_handlers))
                xenbus_write(xbt, "control", "shutdown", "");
 
        err = xenbus_transaction_end(xbt, 0);
@@ -253,8 +255,8 @@ static void shutdown_handler(struct xenbus_watch *watch,
                goto again;
        }
 
-       if (handler->cb) {
-               handler->cb();
+       if (idx < ARRAY_SIZE(shutdown_handlers)) {
+               shutdown_handlers[idx].cb();
        } else {
                pr_info("Ignoring shutdown request: %s\n", str);
                shutting_down = SHUTDOWN_INVALID;
@@ -310,6 +312,9 @@ static struct notifier_block xen_reboot_nb = {
 static int setup_shutdown_watcher(void)
 {
        int err;
+       int idx;
+#define FEATURE_PATH_SIZE (SHUTDOWN_CMD_SIZE + sizeof("feature-"))
+       char node[FEATURE_PATH_SIZE];
 
        err = register_xenbus_watch(&shutdown_watch);
        if (err) {
@@ -326,6 +331,14 @@ static int setup_shutdown_watcher(void)
        }
 #endif
 
+       for (idx = 0; idx < ARRAY_SIZE(shutdown_handlers); idx++) {
+               if (!shutdown_handlers[idx].flag)
+                       continue;
+               snprintf(node, FEATURE_PATH_SIZE, "feature-%s",
+                        shutdown_handlers[idx].command);
+               xenbus_printf(XBT_NIL, "control", node, "%u", 1);
+       }
+
        return 0;
 }
 
index c1010f018bd857985b5bf0ada1f5286f0f68b2bf..1e8be12ebb559880fa5d10f05a2782ad46c36be3 100644 (file)
@@ -364,7 +364,7 @@ out:
 
 static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
 {
-       struct watch_adapter *watch, *tmp_watch;
+       struct watch_adapter *watch;
        char *path, *token;
        int err, rc;
        LIST_HEAD(staging_q);
@@ -399,7 +399,7 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
                }
                list_add(&watch->list, &u->watches);
        } else {
-               list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
+               list_for_each_entry(watch, &u->watches, list) {
                        if (!strcmp(watch->token, token) &&
                            !strcmp(watch->watch.node, path)) {
                                unregister_xenbus_watch(&watch->watch);
index 611a231196757abdb040615acf2a80244360a6a2..6d40a972ffb24585c7e386d5817f53672841e0fc 100644 (file)
@@ -335,7 +335,9 @@ static int backend_state;
 static void xenbus_reset_backend_state_changed(struct xenbus_watch *w,
                                        const char **v, unsigned int l)
 {
-       xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", &backend_state);
+       if (xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i",
+                        &backend_state) != 1)
+               backend_state = XenbusStateUnknown;
        printk(KERN_DEBUG "XENBUS: backend %s %s\n",
                        v[XS_WATCH_PATH], xenbus_strstate(backend_state));
        wake_up(&backend_state_wq);
index 2037e7a77a3767c9e5878838686a6c15a9eea884..d764236072b192d33a0b8eedb3821d7391991067 100644 (file)
@@ -91,11 +91,9 @@ static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
  */
 bool afs_cm_incoming_call(struct afs_call *call)
 {
-       u32 operation_id = ntohl(call->operation_ID);
+       _enter("{CB.OP %u}", call->operation_ID);
 
-       _enter("{CB.OP %u}", operation_id);
-
-       switch (operation_id) {
+       switch (call->operation_ID) {
        case CBCallBack:
                call->type = &afs_SRXCBCallBack;
                return true;
index 96f4d764d1a6784b9bbd3ed7f0313b3b3d49f869..31c616ab9b400a66dfbcd39c12dd87665f88acf9 100644 (file)
@@ -364,7 +364,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                        buffer = kmap(page);
                        ret = afs_extract_data(call, buffer,
                                               call->count, true);
-                       kunmap(buffer);
+                       kunmap(page);
                        if (ret < 0)
                                return ret;
                }
@@ -397,7 +397,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                page = call->reply3;
                buffer = kmap(page);
                memset(buffer + call->count, 0, PAGE_SIZE - call->count);
-               kunmap(buffer);
+               kunmap(page);
        }
 
        _leave(" = 0 [done]");
index 5497c8496055762f18e47a7464bd5b2d71d80caa..535a38d2c1d06f752cd6beae54766c1a9d899527 100644 (file)
@@ -112,7 +112,7 @@ struct afs_call {
        bool                    need_attention; /* T if RxRPC poked us */
        u16                     service_id;     /* RxRPC service ID to call */
        __be16                  port;           /* target UDP port */
-       __be32                  operation_ID;   /* operation ID for an incoming call */
+       u32                     operation_ID;   /* operation ID for an incoming call */
        u32                     count;          /* count for use in unmarshalling */
        __be32                  tmp;            /* place to extract temporary data */
        afs_dataversion_t       store_version;  /* updated version expected from store */
index 477928b259400a33bef35b0ab40608eba6d8b4e5..25f05a8d21b195fffb10f89cff990888fefd1ab2 100644 (file)
@@ -676,10 +676,11 @@ static int afs_deliver_cm_op_id(struct afs_call *call)
        ASSERTCMP(call->offset, <, 4);
 
        /* the operation ID forms the first four bytes of the request data */
-       ret = afs_extract_data(call, &call->operation_ID, 4, true);
+       ret = afs_extract_data(call, &call->tmp, 4, true);
        if (ret < 0)
                return ret;
 
+       call->operation_ID = ntohl(call->tmp);
        call->state = AFS_CALL_AWAIT_REQUEST;
        call->offset = 0;
 
index 1157e13a36d681ecba8e926bb9e91943cfeb6723..428484f2f8413dc6972da9857b3392264b9e6421 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1078,6 +1078,17 @@ static void aio_complete(struct kiocb *kiocb, long res, long res2)
        unsigned tail, pos, head;
        unsigned long   flags;
 
+       if (kiocb->ki_flags & IOCB_WRITE) {
+               struct file *file = kiocb->ki_filp;
+
+               /*
+                * Tell lockdep we inherited freeze protection from submission
+                * thread.
+                */
+               __sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
+               file_end_write(file);
+       }
+
        /*
         * Special case handling for sync iocbs:
         *  - events go directly into the iocb for fast handling
@@ -1392,122 +1403,106 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
        return -EINVAL;
 }
 
-typedef ssize_t (rw_iter_op)(struct kiocb *, struct iov_iter *);
-
-static int aio_setup_vectored_rw(int rw, char __user *buf, size_t len,
-                                struct iovec **iovec,
-                                bool compat,
-                                struct iov_iter *iter)
+static int aio_setup_rw(int rw, struct iocb *iocb, struct iovec **iovec,
+               bool vectored, bool compat, struct iov_iter *iter)
 {
+       void __user *buf = (void __user *)(uintptr_t)iocb->aio_buf;
+       size_t len = iocb->aio_nbytes;
+
+       if (!vectored) {
+               ssize_t ret = import_single_range(rw, buf, len, *iovec, iter);
+               *iovec = NULL;
+               return ret;
+       }
 #ifdef CONFIG_COMPAT
        if (compat)
-               return compat_import_iovec(rw,
-                               (struct compat_iovec __user *)buf,
-                               len, UIO_FASTIOV, iovec, iter);
+               return compat_import_iovec(rw, buf, len, UIO_FASTIOV, iovec,
+                               iter);
 #endif
-       return import_iovec(rw, (struct iovec __user *)buf,
-                               len, UIO_FASTIOV, iovec, iter);
+       return import_iovec(rw, buf, len, UIO_FASTIOV, iovec, iter);
 }
 
-/*
- * aio_run_iocb:
- *     Performs the initial checks and io submission.
- */
-static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
-                           char __user *buf, size_t len, bool compat)
+static inline ssize_t aio_ret(struct kiocb *req, ssize_t ret)
+{
+       switch (ret) {
+       case -EIOCBQUEUED:
+               return ret;
+       case -ERESTARTSYS:
+       case -ERESTARTNOINTR:
+       case -ERESTARTNOHAND:
+       case -ERESTART_RESTARTBLOCK:
+               /*
+                * There's no easy way to restart the syscall since other AIO's
+                * may be already running. Just fail this IO with EINTR.
+                */
+               ret = -EINTR;
+               /*FALLTHRU*/
+       default:
+               aio_complete(req, ret, 0);
+               return 0;
+       }
+}
+
+static ssize_t aio_read(struct kiocb *req, struct iocb *iocb, bool vectored,
+               bool compat)
 {
        struct file *file = req->ki_filp;
-       ssize_t ret;
-       int rw;
-       fmode_t mode;
-       rw_iter_op *iter_op;
        struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
        struct iov_iter iter;
+       ssize_t ret;
 
-       switch (opcode) {
-       case IOCB_CMD_PREAD:
-       case IOCB_CMD_PREADV:
-               mode    = FMODE_READ;
-               rw      = READ;
-               iter_op = file->f_op->read_iter;
-               goto rw_common;
-
-       case IOCB_CMD_PWRITE:
-       case IOCB_CMD_PWRITEV:
-               mode    = FMODE_WRITE;
-               rw      = WRITE;
-               iter_op = file->f_op->write_iter;
-               goto rw_common;
-rw_common:
-               if (unlikely(!(file->f_mode & mode)))
-                       return -EBADF;
-
-               if (!iter_op)
-                       return -EINVAL;
-
-               if (opcode == IOCB_CMD_PREADV || opcode == IOCB_CMD_PWRITEV)
-                       ret = aio_setup_vectored_rw(rw, buf, len,
-                                               &iovec, compat, &iter);
-               else {
-                       ret = import_single_range(rw, buf, len, iovec, &iter);
-                       iovec = NULL;
-               }
-               if (!ret)
-                       ret = rw_verify_area(rw, file, &req->ki_pos,
-                                            iov_iter_count(&iter));
-               if (ret < 0) {
-                       kfree(iovec);
-                       return ret;
-               }
-
-               if (rw == WRITE)
-                       file_start_write(file);
-
-               ret = iter_op(req, &iter);
-
-               if (rw == WRITE)
-                       file_end_write(file);
-               kfree(iovec);
-               break;
-
-       case IOCB_CMD_FDSYNC:
-               if (!file->f_op->aio_fsync)
-                       return -EINVAL;
-
-               ret = file->f_op->aio_fsync(req, 1);
-               break;
+       if (unlikely(!(file->f_mode & FMODE_READ)))
+               return -EBADF;
+       if (unlikely(!file->f_op->read_iter))
+               return -EINVAL;
 
-       case IOCB_CMD_FSYNC:
-               if (!file->f_op->aio_fsync)
-                       return -EINVAL;
+       ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
+       if (ret)
+               return ret;
+       ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
+       if (!ret)
+               ret = aio_ret(req, file->f_op->read_iter(req, &iter));
+       kfree(iovec);
+       return ret;
+}
 
-               ret = file->f_op->aio_fsync(req, 0);
-               break;
+static ssize_t aio_write(struct kiocb *req, struct iocb *iocb, bool vectored,
+               bool compat)
+{
+       struct file *file = req->ki_filp;
+       struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
+       struct iov_iter iter;
+       ssize_t ret;
 
-       default:
-               pr_debug("EINVAL: no operation provided\n");
+       if (unlikely(!(file->f_mode & FMODE_WRITE)))
+               return -EBADF;
+       if (unlikely(!file->f_op->write_iter))
                return -EINVAL;
-       }
 
-       if (ret != -EIOCBQUEUED) {
+       ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
+       if (ret)
+               return ret;
+       ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
+       if (!ret) {
+               req->ki_flags |= IOCB_WRITE;
+               file_start_write(file);
+               ret = aio_ret(req, file->f_op->write_iter(req, &iter));
                /*
-                * There's no easy way to restart the syscall since other AIO's
-                * may be already running. Just fail this IO with EINTR.
+                * We release freeze protection in aio_complete().  Fool lockdep
+                * by telling it the lock got released so that it doesn't
+                * complain about held lock when we return to userspace.
                 */
-               if (unlikely(ret == -ERESTARTSYS || ret == -ERESTARTNOINTR ||
-                            ret == -ERESTARTNOHAND ||
-                            ret == -ERESTART_RESTARTBLOCK))
-                       ret = -EINTR;
-               aio_complete(req, ret, 0);
+               __sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
        }
-
-       return 0;
+       kfree(iovec);
+       return ret;
 }
 
 static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                         struct iocb *iocb, bool compat)
 {
        struct aio_kiocb *req;
+       struct file *file;
        ssize_t ret;
 
        /* enforce forwards compatibility on users */
@@ -1530,7 +1525,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
        if (unlikely(!req))
                return -EAGAIN;
 
-       req->common.ki_filp = fget(iocb->aio_fildes);
+       req->common.ki_filp = file = fget(iocb->aio_fildes);
        if (unlikely(!req->common.ki_filp)) {
                ret = -EBADF;
                goto out_put_req;
@@ -1565,13 +1560,29 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
        req->ki_user_iocb = user_iocb;
        req->ki_user_data = iocb->aio_data;
 
-       ret = aio_run_iocb(&req->common, iocb->aio_lio_opcode,
-                          (char __user *)(unsigned long)iocb->aio_buf,
-                          iocb->aio_nbytes,
-                          compat);
-       if (ret)
-               goto out_put_req;
+       get_file(file);
+       switch (iocb->aio_lio_opcode) {
+       case IOCB_CMD_PREAD:
+               ret = aio_read(&req->common, iocb, false, compat);
+               break;
+       case IOCB_CMD_PWRITE:
+               ret = aio_write(&req->common, iocb, false, compat);
+               break;
+       case IOCB_CMD_PREADV:
+               ret = aio_read(&req->common, iocb, true, compat);
+               break;
+       case IOCB_CMD_PWRITEV:
+               ret = aio_write(&req->common, iocb, true, compat);
+               break;
+       default:
+               pr_debug("invalid aio operation %d\n", iocb->aio_lio_opcode);
+               ret = -EINVAL;
+               break;
+       }
+       fput(file);
 
+       if (ret && ret != -EIOCBQUEUED)
+               goto out_put_req;
        return 0;
 out_put_req:
        put_reqs_available(ctx, 1);
index ccc70d96958d87e0b2db3fc901b513e51a9aa803..d4d8b7e36b2ffe7b84ddb78e4064b606aaee5e01 100644 (file)
@@ -698,7 +698,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
                        ret = btrfs_map_bio(root, comp_bio, mirror_num, 0);
                        if (ret) {
-                               bio->bi_error = ret;
+                               comp_bio->bi_error = ret;
                                bio_endio(comp_bio);
                        }
 
@@ -728,7 +728,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        ret = btrfs_map_bio(root, comp_bio, mirror_num, 0);
        if (ret) {
-               bio->bi_error = ret;
+               comp_bio->bi_error = ret;
                bio_endio(comp_bio);
        }
 
index 210c94ac881888045b59a2f7a0d10f7c698cdebc..4607af38c72e100e6728ff41d8198140dd722d93 100644 (file)
@@ -2647,7 +2647,10 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 
                btrfs_free_delayed_extent_op(extent_op);
                if (ret) {
+                       spin_lock(&delayed_refs->lock);
                        locked_ref->processing = 0;
+                       delayed_refs->num_heads_ready++;
+                       spin_unlock(&delayed_refs->lock);
                        btrfs_delayed_ref_unlock(locked_ref);
                        btrfs_put_delayed_ref(ref);
                        btrfs_debug(fs_info, "run_one_delayed_ref returned %d",
index 66a755150056ed06af2c3bc636b4dc76f45adce5..8ed05d95584a30c2c0cdc4feb1bd2036e93d3276 100644 (file)
@@ -5569,7 +5569,7 @@ void le_bitmap_set(u8 *map, unsigned int start, int len)
                *p |= mask_to_set;
                len -= bits_to_set;
                bits_to_set = BITS_PER_BYTE;
-               mask_to_set = ~(u8)0;
+               mask_to_set = ~0;
                p++;
        }
        if (len) {
@@ -5589,7 +5589,7 @@ void le_bitmap_clear(u8 *map, unsigned int start, int len)
                *p &= ~mask_to_clear;
                len -= bits_to_clear;
                bits_to_clear = BITS_PER_BYTE;
-               mask_to_clear = ~(u8)0;
+               mask_to_clear = ~0;
                p++;
        }
        if (len) {
@@ -5679,7 +5679,7 @@ void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start,
                kaddr[offset] |= mask_to_set;
                len -= bits_to_set;
                bits_to_set = BITS_PER_BYTE;
-               mask_to_set = ~(u8)0;
+               mask_to_set = ~0;
                if (++offset >= PAGE_SIZE && len > 0) {
                        offset = 0;
                        page = eb->pages[++i];
@@ -5721,7 +5721,7 @@ void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start,
                kaddr[offset] &= ~mask_to_clear;
                len -= bits_to_clear;
                bits_to_clear = BITS_PER_BYTE;
-               mask_to_clear = ~(u8)0;
+               mask_to_clear = ~0;
                if (++offset >= PAGE_SIZE && len > 0) {
                        offset = 0;
                        page = eb->pages[++i];
index 2b790bda79988002403f6fe326dcc5535e9f079d..8e3a5a266917c0fac9da9f41ee080262f3394779 100644 (file)
@@ -4605,8 +4605,8 @@ delete:
                        BUG_ON(ret);
                        if (btrfs_should_throttle_delayed_refs(trans, root))
                                btrfs_async_run_delayed_refs(root,
-                                                            trans->transid,
-                                       trans->delayed_ref_updates * 2, 0);
+                                       trans->delayed_ref_updates * 2,
+                                       trans->transid, 0);
                        if (be_nice) {
                                if (truncate_space_check(trans, root,
                                                         extent_num_bytes)) {
@@ -8931,9 +8931,14 @@ again:
         *    So even we call qgroup_free_data(), it won't decrease reserved
         *    space.
         * 2) Not written to disk
-        *    This means the reserved space should be freed here.
+        *    This means the reserved space should be freed here. However,
+        *    if a truncate invalidates the page (by clearing PageDirty)
+        *    and the page is accounted for while allocating extent
+        *    in btrfs_check_data_free_space() we let delayed_ref to
+        *    free the entire extent.
         */
-       btrfs_qgroup_free_data(inode, page_start, PAGE_SIZE);
+       if (PageDirty(page))
+               btrfs_qgroup_free_data(inode, page_start, PAGE_SIZE);
        if (!inode_evicting) {
                clear_extent_bit(tree, page_start, page_end,
                                 EXTENT_LOCKED | EXTENT_DIRTY |
index 18e1aa0f85f5764aa28de59e148a96f49fdacf04..7acbd2cf6192ee8d967236f4b3aeecf1bfc98658 100644 (file)
@@ -3814,6 +3814,11 @@ process_slot:
                }
                btrfs_release_path(path);
                key.offset = next_key_min_offset;
+
+               if (fatal_signal_pending(current)) {
+                       ret = -EINTR;
+                       goto out;
+               }
        }
        ret = 0;
 
index 0ec8ffa37ab09dce21e6d2806c938cce6d4d17a7..c4af0cdb783d0e2ee203ad416abb745fcabd7e02 100644 (file)
@@ -2728,7 +2728,14 @@ static int do_relocation(struct btrfs_trans_handle *trans,
 
                bytenr = btrfs_node_blockptr(upper->eb, slot);
                if (lowest) {
-                       BUG_ON(bytenr != node->bytenr);
+                       if (bytenr != node->bytenr) {
+                               btrfs_err(root->fs_info,
+               "lowest leaf/node mismatch: bytenr %llu node->bytenr %llu slot %d upper %llu",
+                                         bytenr, node->bytenr, slot,
+                                         upper->eb->start);
+                               err = -EIO;
+                               goto next;
+                       }
                } else {
                        if (node->eb->start == bytenr)
                                goto next;
index 01bc36cec26ea132f215aed048bc4f3f5e4e80fd..71261b459863b92ea8e0dff40e99fc79b449286a 100644 (file)
@@ -5805,6 +5805,64 @@ static int changed_extent(struct send_ctx *sctx,
        int ret = 0;
 
        if (sctx->cur_ino != sctx->cmp_key->objectid) {
+
+               if (result == BTRFS_COMPARE_TREE_CHANGED) {
+                       struct extent_buffer *leaf_l;
+                       struct extent_buffer *leaf_r;
+                       struct btrfs_file_extent_item *ei_l;
+                       struct btrfs_file_extent_item *ei_r;
+
+                       leaf_l = sctx->left_path->nodes[0];
+                       leaf_r = sctx->right_path->nodes[0];
+                       ei_l = btrfs_item_ptr(leaf_l,
+                                             sctx->left_path->slots[0],
+                                             struct btrfs_file_extent_item);
+                       ei_r = btrfs_item_ptr(leaf_r,
+                                             sctx->right_path->slots[0],
+                                             struct btrfs_file_extent_item);
+
+                       /*
+                        * We may have found an extent item that has changed
+                        * only its disk_bytenr field and the corresponding
+                        * inode item was not updated. This case happens due to
+                        * very specific timings during relocation when a leaf
+                        * that contains file extent items is COWed while
+                        * relocation is ongoing and its in the stage where it
+                        * updates data pointers. So when this happens we can
+                        * safely ignore it since we know it's the same extent,
+                        * but just at different logical and physical locations
+                        * (when an extent is fully replaced with a new one, we
+                        * know the generation number must have changed too,
+                        * since snapshot creation implies committing the current
+                        * transaction, and the inode item must have been updated
+                        * as well).
+                        * This replacement of the disk_bytenr happens at
+                        * relocation.c:replace_file_extents() through
+                        * relocation.c:btrfs_reloc_cow_block().
+                        */
+                       if (btrfs_file_extent_generation(leaf_l, ei_l) ==
+                           btrfs_file_extent_generation(leaf_r, ei_r) &&
+                           btrfs_file_extent_ram_bytes(leaf_l, ei_l) ==
+                           btrfs_file_extent_ram_bytes(leaf_r, ei_r) &&
+                           btrfs_file_extent_compression(leaf_l, ei_l) ==
+                           btrfs_file_extent_compression(leaf_r, ei_r) &&
+                           btrfs_file_extent_encryption(leaf_l, ei_l) ==
+                           btrfs_file_extent_encryption(leaf_r, ei_r) &&
+                           btrfs_file_extent_other_encoding(leaf_l, ei_l) ==
+                           btrfs_file_extent_other_encoding(leaf_r, ei_r) &&
+                           btrfs_file_extent_type(leaf_l, ei_l) ==
+                           btrfs_file_extent_type(leaf_r, ei_r) &&
+                           btrfs_file_extent_disk_bytenr(leaf_l, ei_l) !=
+                           btrfs_file_extent_disk_bytenr(leaf_r, ei_r) &&
+                           btrfs_file_extent_disk_num_bytes(leaf_l, ei_l) ==
+                           btrfs_file_extent_disk_num_bytes(leaf_r, ei_r) &&
+                           btrfs_file_extent_offset(leaf_l, ei_l) ==
+                           btrfs_file_extent_offset(leaf_r, ei_r) &&
+                           btrfs_file_extent_num_bytes(leaf_l, ei_l) ==
+                           btrfs_file_extent_num_bytes(leaf_r, ei_r))
+                               return 0;
+               }
+
                inconsistent_snapshot_error(sctx, result, "extent");
                return -EIO;
        }
index 528cae123dc9ebaa4c27ea32bd92b05f7d8e2af5..3d33c4e41e5f9a38195436432e54314548076b0d 100644 (file)
@@ -2713,14 +2713,12 @@ static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root,
                                             int index, int error)
 {
        struct btrfs_log_ctx *ctx;
+       struct btrfs_log_ctx *safe;
 
-       if (!error) {
-               INIT_LIST_HEAD(&root->log_ctxs[index]);
-               return;
-       }
-
-       list_for_each_entry(ctx, &root->log_ctxs[index], list)
+       list_for_each_entry_safe(ctx, safe, &root->log_ctxs[index], list) {
+               list_del_init(&ctx->list);
                ctx->log_ret = error;
+       }
 
        INIT_LIST_HEAD(&root->log_ctxs[index]);
 }
@@ -2961,13 +2959,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        mutex_unlock(&root->log_mutex);
 
 out_wake_log_root:
-       /*
-        * We needn't get log_mutex here because we are sure all
-        * the other tasks are blocked.
-        */
+       mutex_lock(&log_root_tree->log_mutex);
        btrfs_remove_all_log_ctxs(log_root_tree, index2, ret);
 
-       mutex_lock(&log_root_tree->log_mutex);
        log_root_tree->log_transid_committed++;
        atomic_set(&log_root_tree->log_commit[index2], 0);
        mutex_unlock(&log_root_tree->log_mutex);
@@ -2978,10 +2972,8 @@ out_wake_log_root:
        if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
                wake_up(&log_root_tree->log_commit_wait[index2]);
 out:
-       /* See above. */
-       btrfs_remove_all_log_ctxs(root, index1, ret);
-
        mutex_lock(&root->log_mutex);
+       btrfs_remove_all_log_ctxs(root, index1, ret);
        root->log_transid_committed++;
        atomic_set(&root->log_commit[index1], 0);
        mutex_unlock(&root->log_mutex);
index 78180d1517307ee7b88dd000d162d7e197b19267..a594c7879cc245a764afb945e37de2b908482951 100644 (file)
@@ -1261,26 +1261,30 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                        return -ECHILD;
 
                op = ceph_snap(dir) == CEPH_SNAPDIR ?
-                       CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
+                       CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_GETATTR;
                req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS);
                if (!IS_ERR(req)) {
                        req->r_dentry = dget(dentry);
-                       req->r_num_caps = 2;
+                       req->r_num_caps = op == CEPH_MDS_OP_GETATTR ? 1 : 2;
 
                        mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
                        if (ceph_security_xattr_wanted(dir))
                                mask |= CEPH_CAP_XATTR_SHARED;
                        req->r_args.getattr.mask = mask;
 
-                       req->r_locked_dir = dir;
                        err = ceph_mdsc_do_request(mdsc, NULL, req);
-                       if (err == 0 || err == -ENOENT) {
-                               if (dentry == req->r_dentry) {
-                                       valid = !d_unhashed(dentry);
-                               } else {
-                                       d_invalidate(req->r_dentry);
-                                       err = -EAGAIN;
-                               }
+                       switch (err) {
+                       case 0:
+                               if (d_really_is_positive(dentry) &&
+                                   d_inode(dentry) == req->r_target_inode)
+                                       valid = 1;
+                               break;
+                       case -ENOENT:
+                               if (d_really_is_negative(dentry))
+                                       valid = 1;
+                               /* Fallthrough */
+                       default:
+                               break;
                        }
                        ceph_mdsc_put_request(req);
                        dout("d_revalidate %p lookup result=%d\n",
index 7bf08825cc1107a20842533fd93b4f2c2d128577..f995e3528a33107bfa1caab3b09b2b5f5af8cf32 100644 (file)
@@ -1272,7 +1272,8 @@ again:
                statret = __ceph_do_getattr(inode, page,
                                            CEPH_STAT_CAP_INLINE_DATA, !!page);
                if (statret < 0) {
-                        __free_page(page);
+                       if (page)
+                               __free_page(page);
                        if (statret == -ENODATA) {
                                BUG_ON(retry_op != READ_INLINE);
                                goto again;
@@ -1769,7 +1770,6 @@ const struct file_operations ceph_file_fops = {
        .fsync = ceph_fsync,
        .lock = ceph_lock,
        .flock = ceph_flock,
-       .splice_read = generic_file_splice_read,
        .splice_write = iter_file_splice_write,
        .unlocked_ioctl = ceph_ioctl,
        .compat_ioctl   = ceph_ioctl,
index bca1b49c1c4b1bc8d2f83e4389a48c1f107de661..ef4d046473256009843b6b4c82e1b5b1e451b02d 100644 (file)
@@ -1511,7 +1511,8 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
                        ceph_fill_dirfrag(d_inode(parent), rinfo->dir_dir);
        }
 
-       if (ceph_frag_is_leftmost(frag) && req->r_readdir_offset == 2) {
+       if (ceph_frag_is_leftmost(frag) && req->r_readdir_offset == 2 &&
+           !(rinfo->hash_order && req->r_path2)) {
                /* note dir version at start of readdir so we can tell
                 * if any dentries get dropped */
                req->r_dir_release_cnt = atomic64_read(&ci->i_release_count);
index a29ffce981879d5fe46f3858ee90c2fd840f98c1..b382e5910eea8bf7cf7a4711fac79104e6466224 100644 (file)
@@ -845,6 +845,8 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
                err = ceph_fs_debugfs_init(fsc);
                if (err < 0)
                        goto fail;
+       } else {
+               root = dget(fsc->sb->s_root);
        }
 
        fsc->mount_state = CEPH_MOUNT_MOUNTED;
index 40b703217977df467aa4b0c4cdc2ffd68423bd30..febc28f9e2c27648e1621531e90cefc482ed2e5d 100644 (file)
@@ -16,7 +16,7 @@
 static int __remove_xattr(struct ceph_inode_info *ci,
                          struct ceph_inode_xattr *xattr);
 
-const struct xattr_handler ceph_other_xattr_handler;
+static const struct xattr_handler ceph_other_xattr_handler;
 
 /*
  * List of handlers for synthetic system.* attributes. Other
@@ -1086,7 +1086,7 @@ static int ceph_set_xattr_handler(const struct xattr_handler *handler,
        return __ceph_setxattr(inode, name, value, size, flags);
 }
 
-const struct xattr_handler ceph_other_xattr_handler = {
+static const struct xattr_handler ceph_other_xattr_handler = {
        .prefix = "",  /* match any name => handlers called with full name */
        .get = ceph_get_xattr_handler,
        .set = ceph_set_xattr_handler,
index 8347c90cf483cefbce4995a107666bba61ae7ef4..5eb04129f93849c2727a517119bc484761160332 100644 (file)
@@ -808,7 +808,11 @@ calc_seckey(struct cifs_ses *ses)
        struct crypto_skcipher *tfm_arc4;
        struct scatterlist sgin, sgout;
        struct skcipher_request *req;
-       unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */
+       unsigned char *sec_key;
+
+       sec_key = kmalloc(CIFS_SESS_KEY_SIZE, GFP_KERNEL);
+       if (sec_key == NULL)
+               return -ENOMEM;
 
        get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
 
@@ -816,7 +820,7 @@ calc_seckey(struct cifs_ses *ses)
        if (IS_ERR(tfm_arc4)) {
                rc = PTR_ERR(tfm_arc4);
                cifs_dbg(VFS, "could not allocate crypto API arc4\n");
-               return rc;
+               goto out;
        }
 
        rc = crypto_skcipher_setkey(tfm_arc4, ses->auth_key.response,
@@ -854,7 +858,8 @@ calc_seckey(struct cifs_ses *ses)
 
 out_free_cipher:
        crypto_free_skcipher(tfm_arc4);
-
+out:
+       kfree(sec_key);
        return rc;
 }
 
index 3f3185febc585f93fb9f88a0b0e96ec49b636f4a..e3fed9249a04f09929e772c0f4c9b0955263b13b 100644 (file)
@@ -3427,6 +3427,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
        __u16 rc = 0;
        struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
        struct posix_acl_xattr_header *local_acl = (void *)pACL;
+       struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
        int count;
        int i;
 
@@ -3453,8 +3454,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
                return 0;
        }
        for (i = 0; i < count; i++) {
-               rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
-                       (struct posix_acl_xattr_entry *)(local_acl + 1));
+               rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
                if (rc != 0) {
                        /* ACE not converted */
                        break;
index aab5227979e2ee27c1858b47f9bf33c275f27633..4547aeddd12b19459d23c6ac9215f01b39b15189 100644 (file)
@@ -412,6 +412,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
                }
        } while (server->tcpStatus == CifsNeedReconnect);
 
+       if (server->tcpStatus == CifsNeedNegotiate)
+               mod_delayed_work(cifsiod_wq, &server->echo, 0);
+
        return rc;
 }
 
@@ -421,17 +424,25 @@ cifs_echo_request(struct work_struct *work)
        int rc;
        struct TCP_Server_Info *server = container_of(work,
                                        struct TCP_Server_Info, echo.work);
-       unsigned long echo_interval = server->echo_interval;
+       unsigned long echo_interval;
+
+       /*
+        * If we need to renegotiate, set echo interval to zero to
+        * immediately call echo service where we can renegotiate.
+        */
+       if (server->tcpStatus == CifsNeedNegotiate)
+               echo_interval = 0;
+       else
+               echo_interval = server->echo_interval;
 
        /*
-        * We cannot send an echo if it is disabled or until the
-        * NEGOTIATE_PROTOCOL request is done, which is indicated by
-        * server->ops->need_neg() == true. Also, no need to ping if
-        * we got a response recently.
+        * We cannot send an echo if it is disabled.
+        * Also, no need to ping if we got a response recently.
         */
 
        if (server->tcpStatus == CifsNeedReconnect ||
-           server->tcpStatus == CifsExiting || server->tcpStatus == CifsNew ||
+           server->tcpStatus == CifsExiting ||
+           server->tcpStatus == CifsNew ||
            (server->ops->can_echo && !server->ops->can_echo(server)) ||
            time_before(jiffies, server->lstrp + echo_interval - HZ))
                goto requeue_echo;
@@ -442,7 +453,7 @@ cifs_echo_request(struct work_struct *work)
                         server->hostname);
 
 requeue_echo:
-       queue_delayed_work(cifsiod_wq, &server->echo, echo_interval);
+       queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
 }
 
 static bool
index 281b768000e664e4d4ef9092d4bb567d003623a0..eb9c92c9b20f5de5e325d7a05e5d055d0816989e 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/freezer.h>
 #include <linux/mm.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -423,7 +424,9 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
        if (core_waiters > 0) {
                struct core_thread *ptr;
 
+               freezer_do_not_count();
                wait_for_completion(&core_state->startup);
+               freezer_count();
                /*
                 * Wait for all the threads to become inactive, so that
                 * all the thread context (extended register state, like
index 61057b7dbddbe17532940f02677668bb9d67152b..98f87fe8f1862d57866b211abeb76e19837d550a 100644 (file)
@@ -151,7 +151,10 @@ static int do_page_crypto(struct inode *inode,
                        struct page *src_page, struct page *dest_page,
                        gfp_t gfp_flags)
 {
-       u8 xts_tweak[FS_XTS_TWEAK_SIZE];
+       struct {
+               __le64 index;
+               u8 padding[FS_XTS_TWEAK_SIZE - sizeof(__le64)];
+       } xts_tweak;
        struct skcipher_request *req = NULL;
        DECLARE_FS_COMPLETION_RESULT(ecr);
        struct scatterlist dst, src;
@@ -171,17 +174,15 @@ static int do_page_crypto(struct inode *inode,
                req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
                page_crypt_complete, &ecr);
 
-       BUILD_BUG_ON(FS_XTS_TWEAK_SIZE < sizeof(index));
-       memcpy(xts_tweak, &index, sizeof(index));
-       memset(&xts_tweak[sizeof(index)], 0,
-                       FS_XTS_TWEAK_SIZE - sizeof(index));
+       BUILD_BUG_ON(sizeof(xts_tweak) != FS_XTS_TWEAK_SIZE);
+       xts_tweak.index = cpu_to_le64(index);
+       memset(xts_tweak.padding, 0, sizeof(xts_tweak.padding));
 
        sg_init_table(&dst, 1);
        sg_set_page(&dst, dest_page, PAGE_SIZE, 0);
        sg_init_table(&src, 1);
        sg_set_page(&src, src_page, PAGE_SIZE, 0);
-       skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE,
-                                       xts_tweak);
+       skcipher_request_set_crypt(req, &src, &dst, PAGE_SIZE, &xts_tweak);
        if (rw == FS_DECRYPT)
                res = crypto_skcipher_decrypt(req);
        else
index 9a28133ac3b848fc04fdab2e5a91b9e671820f56..9b774f4b50c89e0b4c8e6c26b3eae1595f4dc62f 100644 (file)
@@ -39,65 +39,54 @@ static void fname_crypt_complete(struct crypto_async_request *req, int res)
 static int fname_encrypt(struct inode *inode,
                        const struct qstr *iname, struct fscrypt_str *oname)
 {
-       u32 ciphertext_len;
        struct skcipher_request *req = NULL;
        DECLARE_FS_COMPLETION_RESULT(ecr);
        struct fscrypt_info *ci = inode->i_crypt_info;
        struct crypto_skcipher *tfm = ci->ci_ctfm;
        int res = 0;
        char iv[FS_CRYPTO_BLOCK_SIZE];
-       struct scatterlist src_sg, dst_sg;
+       struct scatterlist sg;
        int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
-       char *workbuf, buf[32], *alloc_buf = NULL;
-       unsigned lim;
+       unsigned int lim;
+       unsigned int cryptlen;
 
        lim = inode->i_sb->s_cop->max_namelen(inode);
        if (iname->len <= 0 || iname->len > lim)
                return -EIO;
 
-       ciphertext_len = max(iname->len, (u32)FS_CRYPTO_BLOCK_SIZE);
-       ciphertext_len = round_up(ciphertext_len, padding);
-       ciphertext_len = min(ciphertext_len, lim);
+       /*
+        * Copy the filename to the output buffer for encrypting in-place and
+        * pad it with the needed number of NUL bytes.
+        */
+       cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE);
+       cryptlen = round_up(cryptlen, padding);
+       cryptlen = min(cryptlen, lim);
+       memcpy(oname->name, iname->name, iname->len);
+       memset(oname->name + iname->len, 0, cryptlen - iname->len);
 
-       if (ciphertext_len <= sizeof(buf)) {
-               workbuf = buf;
-       } else {
-               alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
-               if (!alloc_buf)
-                       return -ENOMEM;
-               workbuf = alloc_buf;
-       }
+       /* Initialize the IV */
+       memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
 
-       /* Allocate request */
+       /* Set up the encryption request */
        req = skcipher_request_alloc(tfm, GFP_NOFS);
        if (!req) {
                printk_ratelimited(KERN_ERR
-                       "%s: crypto_request_alloc() failed\n", __func__);
-               kfree(alloc_buf);
+                       "%s: skcipher_request_alloc() failed\n", __func__);
                return -ENOMEM;
        }
        skcipher_request_set_callback(req,
                        CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
                        fname_crypt_complete, &ecr);
+       sg_init_one(&sg, oname->name, cryptlen);
+       skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
 
-       /* Copy the input */
-       memcpy(workbuf, iname->name, iname->len);
-       if (iname->len < ciphertext_len)
-               memset(workbuf + iname->len, 0, ciphertext_len - iname->len);
-
-       /* Initialize IV */
-       memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
-
-       /* Create encryption request */
-       sg_init_one(&src_sg, workbuf, ciphertext_len);
-       sg_init_one(&dst_sg, oname->name, ciphertext_len);
-       skcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
+       /* Do the encryption */
        res = crypto_skcipher_encrypt(req);
        if (res == -EINPROGRESS || res == -EBUSY) {
+               /* Request is being completed asynchronously; wait for it */
                wait_for_completion(&ecr.completion);
                res = ecr.res;
        }
-       kfree(alloc_buf);
        skcipher_request_free(req);
        if (res < 0) {
                printk_ratelimited(KERN_ERR
@@ -105,7 +94,7 @@ static int fname_encrypt(struct inode *inode,
                return res;
        }
 
-       oname->len = ciphertext_len;
+       oname->len = cryptlen;
        return 0;
 }
 
index 82f0285f5d084934d0c13d98d684fbbd3f69f3ed..67fb6d8876d06861a0048dbfe229cb95a867da6c 100644 (file)
@@ -185,7 +185,7 @@ int get_crypt_info(struct inode *inode)
        struct crypto_skcipher *ctfm;
        const char *cipher_str;
        int keysize;
-       u8 raw_key[FS_MAX_KEY_SIZE];
+       u8 *raw_key = NULL;
        int res;
 
        res = fscrypt_initialize();
@@ -238,6 +238,15 @@ retry:
        if (res)
                goto out;
 
+       /*
+        * This cannot be a stack buffer because it is passed to the scatterlist
+        * crypto API as part of key derivation.
+        */
+       res = -ENOMEM;
+       raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS);
+       if (!raw_key)
+               goto out;
+
        if (fscrypt_dummy_context_enabled(inode)) {
                memset(raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
                goto got_key;
@@ -276,7 +285,8 @@ got_key:
        if (res)
                goto out;
 
-       memzero_explicit(raw_key, sizeof(raw_key));
+       kzfree(raw_key);
+       raw_key = NULL;
        if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) != NULL) {
                put_crypt_info(crypt_info);
                goto retry;
@@ -287,7 +297,7 @@ out:
        if (res == -ENOKEY)
                res = 0;
        put_crypt_info(crypt_info);
-       memzero_explicit(raw_key, sizeof(raw_key));
+       kzfree(raw_key);
        return res;
 }
 
index ed115acb5dee04bd15726ed2b9f368f6d13315cc..6865663aac69690f7ccdce030c48488a13ce917b 100644 (file)
@@ -109,6 +109,8 @@ int fscrypt_process_policy(struct file *filp,
        if (ret)
                return ret;
 
+       inode_lock(inode);
+
        if (!inode_has_encryption_context(inode)) {
                if (!S_ISDIR(inode->i_mode))
                        ret = -EINVAL;
@@ -127,6 +129,8 @@ int fscrypt_process_policy(struct file *filp,
                ret = -EINVAL;
        }
 
+       inode_unlock(inode);
+
        mnt_drop_write_file(filp);
        return ret;
 }
index 6fcfb3f7b137951b133d3db95431c23bc2d4677f..4e497b9ee71ee96d0647721e4649feff7adaf7c1 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
 {
        struct page *page;
        int ret;
+       unsigned int gup_flags = FOLL_FORCE;
 
 #ifdef CONFIG_STACK_GROWSUP
        if (write) {
@@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
                        return NULL;
        }
 #endif
+
+       if (write)
+               gup_flags |= FOLL_WRITE;
+
        /*
         * We are doing an exec().  'current' is the process
         * doing the exec and bprm->mm is the new process's mm.
         */
-       ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
-                       1, &page, NULL);
+       ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
+                       &page, NULL);
        if (ret <= 0)
                return NULL;
 
index 79101651fe9ed2a6ccb3682ba39c590755b5bb00..42f9a0a0c4caf09722bc69fa278d509a7b7f16b3 100644 (file)
@@ -137,7 +137,7 @@ Espan:
 bad_entry:
        EXOFS_ERR(
                "ERROR [exofs_check_page]: bad entry in directory(0x%lx): %s - "
-               "offset=%lu, inode=0x%llu, rec_len=%d, name_len=%d\n",
+               "offset=%lu, inode=0x%llx, rec_len=%d, name_len=%d\n",
                dir->i_ino, error, (page->index<<PAGE_SHIFT)+offs,
                _LLU(le64_to_cpu(p->inode_no)),
                rec_len, p->name_len);
index d831e24dc88534844aa03a98ba2963f9d3e4b3d0..41b8b44a391cb5dc8ed833cb95b632424372e038 100644 (file)
@@ -622,7 +622,7 @@ static int ext2_get_blocks(struct inode *inode,
                           u32 *bno, bool *new, bool *boundary,
                           int create)
 {
-       int err = -EIO;
+       int err;
        int offsets[4];
        Indirect chain[4];
        Indirect *partial;
@@ -639,7 +639,7 @@ static int ext2_get_blocks(struct inode *inode,
        depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
 
        if (depth == 0)
-               return (err);
+               return -EIO;
 
        partial = ext2_get_branch(inode, depth, offsets, chain, &err);
        /* Simplest case - block found, no allocation needed */
@@ -761,7 +761,6 @@ static int ext2_get_blocks(struct inode *inode,
        ext2_splice_branch(inode, iblock, partial, indirect_blks, count);
        mutex_unlock(&ei->truncate_mutex);
 got_it:
-       *bno = le32_to_cpu(chain[depth-1].key);
        if (count > blocks_to_boundary)
                *boundary = true;
        err = count;
@@ -772,6 +771,8 @@ cleanup:
                brelse(partial->bh);
                partial--;
        }
+       if (err > 0)
+               *bno = le32_to_cpu(chain[depth-1].key);
        return err;
 }
 
index 02ddec6d8a7da3135cef70cc2960bd8789f20378..fdb19543af1e62f9b990c944b92fd5dce0fd644a 100644 (file)
@@ -128,12 +128,12 @@ static void debug_print_tree(struct ext4_sb_info *sbi)
        node = rb_first(&sbi->system_blks);
        while (node) {
                entry = rb_entry(node, struct ext4_system_zone, node);
-               printk("%s%llu-%llu", first ? "" : ", ",
+               printk(KERN_CONT "%s%llu-%llu", first ? "" : ", ",
                       entry->start_blk, entry->start_blk + entry->count - 1);
                first = 0;
                node = rb_next(node);
        }
-       printk("\n");
+       printk(KERN_CONT "\n");
 }
 
 int ext4_setup_system_zone(struct super_block *sb)
index 282a51b07c5769e89a2064e12dfad53650183614..a8a750f596217062fa4e5d565ea44752e3e6ba50 100644 (file)
@@ -235,6 +235,7 @@ struct ext4_io_submit {
 #define        EXT4_MAX_BLOCK_SIZE             65536
 #define EXT4_MIN_BLOCK_LOG_SIZE                10
 #define EXT4_MAX_BLOCK_LOG_SIZE                16
+#define EXT4_MAX_CLUSTER_LOG_SIZE      30
 #ifdef __KERNEL__
 # define EXT4_BLOCK_SIZE(s)            ((s)->s_blocksize)
 #else
index 3ef1df6ae9ec6f67102c52cf9624a317e321d19b..1aba469f82209fe40d602579a17964346749e024 100644 (file)
 #ifdef CONFIG_EXT4_DEBUG
 extern ushort ext4_mballoc_debug;
 
-#define mb_debug(n, fmt, a...)                                         \
-       do {                                                            \
-               if ((n) <= ext4_mballoc_debug) {                        \
-                       printk(KERN_DEBUG "(%s, %d): %s: ",             \
-                              __FILE__, __LINE__, __func__);           \
-                       printk(fmt, ## a);                              \
-               }                                                       \
-       } while (0)
+#define mb_debug(n, fmt, ...)                                          \
+do {                                                                   \
+       if ((n) <= ext4_mballoc_debug) {                                \
+               printk(KERN_DEBUG "(%s, %d): %s: " fmt,                 \
+                      __FILE__, __LINE__, __func__, ##__VA_ARGS__);    \
+       }                                                               \
+} while (0)
 #else
-#define mb_debug(n, fmt, a...)         no_printk(fmt, ## a)
+#define mb_debug(n, fmt, ...)  no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 #define EXT4_MB_HISTORY_ALLOC          1       /* allocation */
index f92f10d4f66ace5dd13c528ac0f2ca005e066667..104f8bfba71822dd55f05b0caaebbf41aa2eb941 100644 (file)
@@ -577,12 +577,13 @@ static inline unsigned dx_node_limit(struct inode *dir)
 static void dx_show_index(char * label, struct dx_entry *entries)
 {
        int i, n = dx_get_count (entries);
-       printk(KERN_DEBUG "%s index ", label);
+       printk(KERN_DEBUG "%s index", label);
        for (i = 0; i < n; i++) {
-               printk("%x->%lu ", i ? dx_get_hash(entries + i) :
-                               0, (unsigned long)dx_get_block(entries + i));
+               printk(KERN_CONT " %x->%lu",
+                      i ? dx_get_hash(entries + i) : 0,
+                      (unsigned long)dx_get_block(entries + i));
        }
-       printk("\n");
+       printk(KERN_CONT "\n");
 }
 
 struct stats
@@ -679,7 +680,7 @@ static struct stats dx_show_leaf(struct inode *dir,
                }
                de = ext4_next_entry(de, size);
        }
-       printk("(%i)\n", names);
+       printk(KERN_CONT "(%i)\n", names);
        return (struct stats) { names, space, 1 };
 }
 
@@ -798,7 +799,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir,
                q = entries + count - 1;
                while (p <= q) {
                        m = p + (q - p) / 2;
-                       dxtrace(printk("."));
+                       dxtrace(printk(KERN_CONT "."));
                        if (dx_get_hash(m) > hash)
                                q = m - 1;
                        else
@@ -810,7 +811,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir,
                        at = entries;
                        while (n--)
                        {
-                               dxtrace(printk(","));
+                               dxtrace(printk(KERN_CONT ","));
                                if (dx_get_hash(++at) > hash)
                                {
                                        at--;
@@ -821,7 +822,8 @@ dx_probe(struct ext4_filename *fname, struct inode *dir,
                }
 
                at = p - 1;
-               dxtrace(printk(" %x->%u\n", at == entries ? 0 : dx_get_hash(at),
+               dxtrace(printk(KERN_CONT " %x->%u\n",
+                              at == entries ? 0 : dx_get_hash(at),
                               dx_get_block(at)));
                frame->entries = entries;
                frame->at = at;
index 6db81fbcbaa6cce558b6ef9f7e613e8284e898a6..52b0530c5d65a95fa0512b29cb2b3645d0277b69 100644 (file)
@@ -597,14 +597,15 @@ void __ext4_std_error(struct super_block *sb, const char *function,
 void __ext4_abort(struct super_block *sb, const char *function,
                unsigned int line, const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
 
        save_error_info(sb, function, line);
        va_start(args, fmt);
-       printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: ", sb->s_id,
-              function, line);
-       vprintk(fmt, args);
-       printk("\n");
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: %pV\n",
+              sb->s_id, function, line, &vaf);
        va_end(args);
 
        if ((sb->s_flags & MS_RDONLY) == 0) {
@@ -2715,12 +2716,12 @@ static void print_daily_error_info(unsigned long arg)
                       es->s_first_error_func,
                       le32_to_cpu(es->s_first_error_line));
                if (es->s_first_error_ino)
-                       printk(": inode %u",
+                       printk(KERN_CONT ": inode %u",
                               le32_to_cpu(es->s_first_error_ino));
                if (es->s_first_error_block)
-                       printk(": block %llu", (unsigned long long)
+                       printk(KERN_CONT ": block %llu", (unsigned long long)
                               le64_to_cpu(es->s_first_error_block));
-               printk("\n");
+               printk(KERN_CONT "\n");
        }
        if (es->s_last_error_time) {
                printk(KERN_NOTICE "EXT4-fs (%s): last error at time %u: %.*s:%d",
@@ -2729,12 +2730,12 @@ static void print_daily_error_info(unsigned long arg)
                       es->s_last_error_func,
                       le32_to_cpu(es->s_last_error_line));
                if (es->s_last_error_ino)
-                       printk(": inode %u",
+                       printk(KERN_CONT ": inode %u",
                               le32_to_cpu(es->s_last_error_ino));
                if (es->s_last_error_block)
-                       printk(": block %llu", (unsigned long long)
+                       printk(KERN_CONT ": block %llu", (unsigned long long)
                               le64_to_cpu(es->s_last_error_block));
-               printk("\n");
+               printk(KERN_CONT "\n");
        }
        mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ);  /* Once a day */
 }
@@ -3564,7 +3565,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (blocksize < EXT4_MIN_BLOCK_SIZE ||
            blocksize > EXT4_MAX_BLOCK_SIZE) {
                ext4_msg(sb, KERN_ERR,
-                      "Unsupported filesystem blocksize %d", blocksize);
+                      "Unsupported filesystem blocksize %d (%d log_block_size)",
+                        blocksize, le32_to_cpu(es->s_log_block_size));
+               goto failed_mount;
+       }
+       if (le32_to_cpu(es->s_log_block_size) >
+           (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
+               ext4_msg(sb, KERN_ERR,
+                        "Invalid log block size: %u",
+                        le32_to_cpu(es->s_log_block_size));
                goto failed_mount;
        }
 
@@ -3696,6 +3705,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                 "block size (%d)", clustersize, blocksize);
                        goto failed_mount;
                }
+               if (le32_to_cpu(es->s_log_cluster_size) >
+                   (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Invalid log cluster size: %u",
+                                le32_to_cpu(es->s_log_cluster_size));
+                       goto failed_mount;
+               }
                sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) -
                        le32_to_cpu(es->s_log_block_size);
                sbi->s_clusters_per_group =
index 73bcfd41f5f262453e729fc11c4604b5109de842..42145be5c6b4dea4258b35586693ae336f047d25 100644 (file)
@@ -223,14 +223,18 @@ static struct attribute *ext4_attrs[] = {
 EXT4_ATTR_FEATURE(lazy_itable_init);
 EXT4_ATTR_FEATURE(batched_discard);
 EXT4_ATTR_FEATURE(meta_bg_resize);
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
 EXT4_ATTR_FEATURE(encryption);
+#endif
 EXT4_ATTR_FEATURE(metadata_csum_seed);
 
 static struct attribute *ext4_feat_attrs[] = {
        ATTR_LIST(lazy_itable_init),
        ATTR_LIST(batched_discard),
        ATTR_LIST(meta_bg_resize),
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
        ATTR_LIST(encryption),
+#endif
        ATTR_LIST(metadata_csum_seed),
        NULL,
 };
index c15d63389957bda0926a187da5df4bfcf7a9668c..d77be9e9f5352f2eedd1ab005dba20a899bbbbf6 100644 (file)
 #include "acl.h"
 
 #ifdef EXT4_XATTR_DEBUG
-# define ea_idebug(inode, f...) do { \
-               printk(KERN_DEBUG "inode %s:%lu: ", \
-                       inode->i_sb->s_id, inode->i_ino); \
-               printk(f); \
-               printk("\n"); \
-       } while (0)
-# define ea_bdebug(bh, f...) do { \
-               printk(KERN_DEBUG "block %pg:%lu: ",               \
-                      bh->b_bdev, (unsigned long) bh->b_blocknr); \
-               printk(f); \
-               printk("\n"); \
-       } while (0)
+# define ea_idebug(inode, fmt, ...)                                    \
+       printk(KERN_DEBUG "inode %s:%lu: " fmt "\n",                    \
+              inode->i_sb->s_id, inode->i_ino, ##__VA_ARGS__)
+# define ea_bdebug(bh, fmt, ...)                                       \
+       printk(KERN_DEBUG "block %pg:%lu: " fmt "\n",                   \
+              bh->b_bdev, (unsigned long)bh->b_blocknr, ##__VA_ARGS__)
 #else
 # define ea_idebug(inode, fmt, ...)    no_printk(fmt, ##__VA_ARGS__)
 # define ea_bdebug(bh, fmt, ...)       no_printk(fmt, ##__VA_ARGS__)
@@ -241,7 +235,7 @@ __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header,
        int error = -EFSCORRUPTED;
 
        if (((void *) header >= end) ||
-           (header->h_magic != le32_to_cpu(EXT4_XATTR_MAGIC)))
+           (header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)))
                goto errout;
        error = ext4_xattr_check_names(entry, end, entry);
 errout:
index 93985c64d8a8bef1328ddd5f35cc7d047f41fc3a..6f14ee923acd2b4cf75f93bed945f6fc04b79c93 100644 (file)
@@ -852,16 +852,16 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
 
        for (segno = start_segno; segno < end_segno; segno++) {
 
-               if (get_valid_blocks(sbi, segno, 1) == 0 ||
-                                       unlikely(f2fs_cp_error(sbi)))
-                       goto next;
-
                /* find segment summary of victim */
                sum_page = find_get_page(META_MAPPING(sbi),
                                        GET_SUM_BLOCK(sbi, segno));
-               f2fs_bug_on(sbi, !PageUptodate(sum_page));
                f2fs_put_page(sum_page, 0);
 
+               if (get_valid_blocks(sbi, segno, 1) == 0 ||
+                               !PageUptodate(sum_page) ||
+                               unlikely(f2fs_cp_error(sbi)))
+                       goto next;
+
                sum = page_address(sum_page);
                f2fs_bug_on(sbi, type != GET_SUM_TYPE((&sum->footer)));
 
index 6a4d0e5418a179def0e5d4da4d3adbbcf3a82cd0..096f79997f75adf9603c4c6367635588535a8ae3 100644 (file)
@@ -286,6 +286,11 @@ const struct dentry_operations fuse_dentry_operations = {
        .d_release      = fuse_dentry_release,
 };
 
+const struct dentry_operations fuse_root_dentry_operations = {
+       .d_init         = fuse_dentry_init,
+       .d_release      = fuse_dentry_release,
+};
+
 int fuse_valid_type(int m)
 {
        return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
@@ -1734,8 +1739,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
                 * This should be done on write(), truncate() and chown().
                 */
                if (!fc->handle_killpriv) {
-                       int kill;
-
                        /*
                         * ia_mode calculation may have used stale i_mode.
                         * Refresh and recalculate.
@@ -1745,12 +1748,11 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
                                return ret;
 
                        attr->ia_mode = inode->i_mode;
-                       kill = should_remove_suid(entry);
-                       if (kill & ATTR_KILL_SUID) {
+                       if (inode->i_mode & S_ISUID) {
                                attr->ia_valid |= ATTR_MODE;
                                attr->ia_mode &= ~S_ISUID;
                        }
-                       if (kill & ATTR_KILL_SGID) {
+                       if ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
                                attr->ia_valid |= ATTR_MODE;
                                attr->ia_mode &= ~S_ISGID;
                        }
index abc66a6237fd0ebd9bbafbf893b21b97874d01dc..2401c5dabb2a227b6511be01b1589ffa5180e636 100644 (file)
@@ -1985,6 +1985,10 @@ static int fuse_write_end(struct file *file, struct address_space *mapping,
 {
        struct inode *inode = page->mapping->host;
 
+       /* Haven't copied anything?  Skip zeroing, size extending, dirtying. */
+       if (!copied)
+               goto unlock;
+
        if (!PageUptodate(page)) {
                /* Zero any unwritten bytes at the end of the page */
                size_t endoff = (pos + copied) & ~PAGE_MASK;
@@ -1995,6 +1999,8 @@ static int fuse_write_end(struct file *file, struct address_space *mapping,
 
        fuse_write_update_size(inode, pos + copied);
        set_page_dirty(page);
+
+unlock:
        unlock_page(page);
        put_page(page);
 
index 0dfbb136e59a8515e3ee9fe77d9996c22722d50c..91307940c8ac5e921b08133a04ca0b65283fd308 100644 (file)
@@ -692,6 +692,7 @@ static inline u64 get_node_id(struct inode *inode)
 extern const struct file_operations fuse_dev_operations;
 
 extern const struct dentry_operations fuse_dentry_operations;
+extern const struct dentry_operations fuse_root_dentry_operations;
 
 /**
  * Inode to nodeid comparison.
index 17141099f2e783fc6f2c10eabda326e13728b2f5..6fe6a88ecb4afd9eaaad1b0c75fe961108efc64a 100644 (file)
@@ -1131,10 +1131,11 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 
        err = -ENOMEM;
        root = fuse_get_root_inode(sb, d.rootmode);
+       sb->s_d_op = &fuse_root_dentry_operations;
        root_dentry = d_make_root(root);
        if (!root_dentry)
                goto err_dev_free;
-       /* only now - we want root dentry with NULL ->d_op */
+       /* Root dentry doesn't have .d_revalidate */
        sb->s_d_op = &fuse_dentry_operations;
 
        init_req = fuse_request_alloc(0);
index 013d1d36fbbf7fa3e3f321a05c8a5e956b731cb6..a8ee8c33ca782dbe4a4c17f42bf91fda9e83a523 100644 (file)
@@ -433,8 +433,7 @@ iomap_page_mkwrite_actor(struct inode *inode, loff_t pos, loff_t length,
        struct page *page = data;
        int ret;
 
-       ret = __block_write_begin_int(page, pos & ~PAGE_MASK, length,
-                       NULL, iomap);
+       ret = __block_write_begin_int(page, pos, length, NULL, iomap);
        if (ret)
                return ret;
 
@@ -561,7 +560,7 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
        }
 
        while (len > 0) {
-               ret = iomap_apply(inode, start, len, 0, ops, &ctx,
+               ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx,
                                iomap_fiemap_actor);
                /* inode with no (attribute) mapping will give ENOENT */
                if (ret == -ENOENT)
index ad0c745ebad72e89fd987e0f67de5e61f525ff2a..871c8b39209913d95708398688df19ca31b0eba7 100644 (file)
@@ -687,6 +687,11 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
        pri_bh = NULL;
 
 root_found:
+       /* We don't support read-write mounts */
+       if (!(s->s_flags & MS_RDONLY)) {
+               error = -EACCES;
+               goto out_freebh;
+       }
 
        if (joliet_level && (pri == NULL || !opt.rock)) {
                /* This is the case of Joliet with the norock mount flag.
@@ -1501,9 +1506,6 @@ struct inode *__isofs_iget(struct super_block *sb,
 static struct dentry *isofs_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
-       /* We don't support read-write mounts */
-       if (!(flags & MS_RDONLY))
-               return ERR_PTR(-EACCES);
        return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
 }
 
index 98b3eb7d8eaf64d5eb006801aeb130ff8503f593..0ec137310320f080316c5e6111198b842a77303e 100644 (file)
@@ -377,9 +377,9 @@ repeat:
                        {
                                int p;
                                for (p = 0; p < rr->u.ER.len_id; p++)
-                                       printk("%c", rr->u.ER.data[p]);
+                                       printk(KERN_CONT "%c", rr->u.ER.data[p]);
                        }
-                       printk("\n");
+                       printk(KERN_CONT "\n");
                        break;
                case SIG('P', 'X'):
                        inode->i_mode = isonum_733(rr->u.PX.mode);
index 3d8246a9faa454ec8e3774b1b6320ce0a12f67da..e1652665bd93d0cf30dece02b5a1b7692fdec811 100644 (file)
@@ -1149,6 +1149,7 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
                JBUFFER_TRACE(jh, "file as BJ_Reserved");
                spin_lock(&journal->j_list_lock);
                __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
+               spin_unlock(&journal->j_list_lock);
        } else if (jh->b_transaction == journal->j_committing_transaction) {
                /* first access by this transaction */
                jh->b_modified = 0;
@@ -1156,8 +1157,8 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
                JBUFFER_TRACE(jh, "set next transaction");
                spin_lock(&journal->j_list_lock);
                jh->b_next_transaction = transaction;
+               spin_unlock(&journal->j_list_lock);
        }
-       spin_unlock(&journal->j_list_lock);
        jbd_unlock_bh_state(bh);
 
        /*
index 2bcb86e6e6ca0988cbe4337c970247869db34a24..78219d5644e90aacaf3aeb9fdfe2a234f4e31b84 100644 (file)
@@ -911,6 +911,7 @@ const struct file_operations kernfs_file_fops = {
        .open           = kernfs_fop_open,
        .release        = kernfs_fop_release,
        .poll           = kernfs_fop_poll,
+       .fsync          = noop_fsync,
 };
 
 /**
index ce93b416b490fa558589a6bdd2bb620ffb108fcc..22c5b4aa49611ac46cb50dbf4fc8ef25ec500b34 100644 (file)
@@ -1609,6 +1609,7 @@ int fcntl_getlease(struct file *filp)
 
        ctx = smp_load_acquire(&inode->i_flctx);
        if (ctx && !list_empty_careful(&ctx->flc_lease)) {
+               percpu_down_read_preempt_disable(&file_rwsem);
                spin_lock(&ctx->flc_lock);
                time_out_leases(inode, &dispose);
                list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
@@ -1618,6 +1619,8 @@ int fcntl_getlease(struct file *filp)
                        break;
                }
                spin_unlock(&ctx->flc_lock);
+               percpu_up_read_preempt_enable(&file_rwsem);
+
                locks_dispose_list(&dispose);
        }
        return type;
@@ -2529,11 +2532,14 @@ locks_remove_lease(struct file *filp, struct file_lock_context *ctx)
        if (list_empty(&ctx->flc_lease))
                return;
 
+       percpu_down_read_preempt_disable(&file_rwsem);
        spin_lock(&ctx->flc_lock);
        list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list)
                if (filp == fl->fl_file)
                        lease_modify(fl, F_UNLCK, &dispose);
        spin_unlock(&ctx->flc_lock);
+       percpu_up_read_preempt_enable(&file_rwsem);
+
        locks_dispose_list(&dispose);
 }
 
index 217847679f0eac675492ac049cbc0a42a6f75066..2905479f214a4654223ec90ae13e21138ac2be4d 100644 (file)
@@ -344,9 +344,10 @@ static void bl_write_cleanup(struct work_struct *work)
                u64 start = hdr->args.offset & (loff_t)PAGE_MASK;
                u64 end = (hdr->args.offset + hdr->args.count +
                        PAGE_SIZE - 1) & (loff_t)PAGE_MASK;
+               u64 lwb = hdr->args.offset + hdr->args.count;
 
                ext_tree_mark_written(bl, start >> SECTOR_SHIFT,
-                                       (end - start) >> SECTOR_SHIFT, end);
+                                       (end - start) >> SECTOR_SHIFT, lwb);
        }
 
        pnfs_ld_write_done(hdr);
index 532d8e242d4d76c44413d6c814c7548094614ebe..484bebc20bca6a502cc621106d7f34975b48dedc 100644 (file)
@@ -197,7 +197,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
        }
 
        ret = -EPROTONOSUPPORT;
-       if (minorversion == 0)
+       if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
                ret = nfs4_callback_up_net(serv, net);
        else if (xprt->ops->bc_up)
                ret = xprt->ops->bc_up(serv, net);
index 7555ba889d1fce916cc96b8f23c03ad4d6037366..ebecfb8fba067cd4316e1c59e12c472c97d930a6 100644 (file)
@@ -314,7 +314,8 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
                /* Match the full socket address */
                if (!rpc_cmp_addr_port(sap, clap))
                        /* Match all xprt_switch full socket addresses */
-                       if (!rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
+                       if (IS_ERR(clp->cl_rpcclient) ||
+                            !rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
                                                           sap))
                                continue;
 
index c8162c660c440bb28eb7e31fbd33ce1b4c3b1438..5551e8ef67fd0b64faa92688a8fa38b05bbb0c78 100644 (file)
@@ -98,7 +98,7 @@ rename_retry:
                return end;
        }
        namelen = strlen(base);
-       if (flags & NFS_PATH_CANONICAL) {
+       if (*end == '/') {
                /* Strip off excess slashes in base string */
                while (namelen > 0 && base[namelen - 1] == '/')
                        namelen--;
index 9b3a82abab079f0a03047260ed2ea4e3ee9154ed..1452177c822dbc4a1be8d7e164de88d636764aed 100644 (file)
@@ -542,6 +542,13 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
        return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0;
 }
 
+static inline bool nfs4_state_match_open_stateid_other(const struct nfs4_state *state,
+               const nfs4_stateid *stateid)
+{
+       return test_bit(NFS_OPEN_STATE, &state->flags) &&
+               nfs4_stateid_match_other(&state->open_stateid, stateid);
+}
+
 #else
 
 #define nfs4_close_state(a, b) do { } while (0)
index ad917bd72b38c3b213ce994ee2d063b111cb6277..241da19b7da4a54a45b1a2bd6cae4cab8cab4dde 100644 (file)
@@ -1451,7 +1451,6 @@ static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
 }
 
 static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
-               nfs4_stateid *arg_stateid,
                nfs4_stateid *stateid, fmode_t fmode)
 {
        clear_bit(NFS_O_RDWR_STATE, &state->flags);
@@ -1469,10 +1468,9 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
        }
        if (stateid == NULL)
                return;
-       /* Handle races with OPEN */
-       if (!nfs4_stateid_match_other(arg_stateid, &state->open_stateid) ||
-           (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
-           !nfs4_stateid_is_newer(stateid, &state->open_stateid))) {
+       /* Handle OPEN+OPEN_DOWNGRADE races */
+       if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
+           !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
                nfs_resync_open_stateid_locked(state);
                return;
        }
@@ -1486,7 +1484,9 @@ static void nfs_clear_open_stateid(struct nfs4_state *state,
        nfs4_stateid *stateid, fmode_t fmode)
 {
        write_seqlock(&state->seqlock);
-       nfs_clear_open_stateid_locked(state, arg_stateid, stateid, fmode);
+       /* Ignore, if the CLOSE argment doesn't match the current stateid */
+       if (nfs4_state_match_open_stateid_other(state, arg_stateid))
+               nfs_clear_open_stateid_locked(state, stateid, fmode);
        write_sequnlock(&state->seqlock);
        if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
                nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
@@ -1545,7 +1545,7 @@ static int update_open_stateid(struct nfs4_state *state,
        struct nfs_client *clp = server->nfs_client;
        struct nfs_inode *nfsi = NFS_I(state->inode);
        struct nfs_delegation *deleg_cur;
-       nfs4_stateid freeme = {0};
+       nfs4_stateid freeme = { };
        int ret = 0;
 
        fmode &= (FMODE_READ|FMODE_WRITE);
@@ -2564,15 +2564,23 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
 static int nfs41_check_expired_locks(struct nfs4_state *state)
 {
        int status, ret = NFS_OK;
-       struct nfs4_lock_state *lsp;
+       struct nfs4_lock_state *lsp, *prev = NULL;
        struct nfs_server *server = NFS_SERVER(state->inode);
 
        if (!test_bit(LK_STATE_IN_USE, &state->flags))
                goto out;
+
+       spin_lock(&state->state_lock);
        list_for_each_entry(lsp, &state->lock_states, ls_locks) {
                if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
                        struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
 
+                       atomic_inc(&lsp->ls_count);
+                       spin_unlock(&state->state_lock);
+
+                       nfs4_put_lock_state(prev);
+                       prev = lsp;
+
                        status = nfs41_test_and_free_expired_stateid(server,
                                        &lsp->ls_stateid,
                                        cred);
@@ -2585,10 +2593,14 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
                                        set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
                        } else if (status != NFS_OK) {
                                ret = status;
-                               break;
+                               nfs4_put_lock_state(prev);
+                               goto out;
                        }
+                       spin_lock(&state->state_lock);
                }
-       };
+       }
+       spin_unlock(&state->state_lock);
+       nfs4_put_lock_state(prev);
 out:
        return ret;
 }
@@ -3122,7 +3134,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        } else if (is_rdwr)
                calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
 
-       if (!nfs4_valid_open_stateid(state))
+       if (!nfs4_valid_open_stateid(state) ||
+           test_bit(NFS_OPEN_STATE, &state->flags) == 0)
                call_close = 0;
        spin_unlock(&state->owner->so_lock);
 
@@ -5569,6 +5582,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
        switch (task->tk_status) {
        case 0:
                renew_lease(data->res.server, data->timestamp);
+               break;
        case -NFS4ERR_ADMIN_REVOKED:
        case -NFS4ERR_DELEG_REVOKED:
        case -NFS4ERR_EXPIRED:
@@ -5579,8 +5593,6 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
        case -NFS4ERR_OLD_STATEID:
        case -NFS4ERR_STALE_STATEID:
                task->tk_status = 0;
-               if (data->roc)
-                       pnfs_roc_set_barrier(data->inode, data->roc_barrier);
                break;
        default:
                if (nfs4_async_handle_error(task, data->res.server,
@@ -5590,6 +5602,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
                }
        }
        data->rpc_status = task->tk_status;
+       if (data->roc && data->rpc_status == 0)
+               pnfs_roc_set_barrier(data->inode, data->roc_barrier);
 }
 
 static void nfs4_delegreturn_release(void *calldata)
index b62973045a3e048016f1af48f761fdb152f3908d..a61350f75c741d734475cfa38903118d673b76aa 100644 (file)
@@ -178,12 +178,14 @@ static int nfs4_slot_get_seqid(struct nfs4_slot_table  *tbl, u32 slotid,
        __must_hold(&tbl->slot_tbl_lock)
 {
        struct nfs4_slot *slot;
+       int ret;
 
        slot = nfs4_lookup_slot(tbl, slotid);
-       if (IS_ERR(slot))
-               return PTR_ERR(slot);
-       *seq_nr = slot->seq_nr;
-       return 0;
+       ret = PTR_ERR_OR_ZERO(slot);
+       if (!ret)
+               *seq_nr = slot->seq_nr;
+
+       return ret;
 }
 
 /*
@@ -196,7 +198,7 @@ static int nfs4_slot_get_seqid(struct nfs4_slot_table  *tbl, u32 slotid,
 static bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl,
                u32 slotid, u32 seq_nr)
 {
-       u32 cur_seq;
+       u32 cur_seq = 0;
        bool ret = false;
 
        spin_lock(&tbl->slot_tbl_lock);
index 5f4281ec5f72c3556d76a479854d6fb378d03124..0959c96616623f876a5905deb6e03c1a438fe338 100644 (file)
@@ -1547,6 +1547,7 @@ restart:
                                ssleep(1);
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_STALE_STATEID:
+                       case -NFS4ERR_OLD_STATEID:
                        case -NFS4ERR_BAD_STATEID:
                        case -NFS4ERR_RECLAIM_BAD:
                        case -NFS4ERR_RECLAIM_CONFLICT:
index 56b2d96f9103e42c57e5dd490f2561c8a10c554a..259ef85f435aa7f9e0b0e4d06d3ce24a9e7a3ad3 100644 (file)
@@ -146,6 +146,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
        u32 id;
        int i;
 
+       if (fsinfo->nlayouttypes == 0)
+               goto out_no_driver;
        if (!(server->nfs_client->cl_exchange_flags &
                 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
                printk(KERN_ERR "NFS: %s: cl_exchange_flags 0x%x\n",
index b10d557f9c9ef0033a6dcbcfcf30141745132e8f..ee36efd5aece83e08712bb0d839423bb30b8674a 100644 (file)
@@ -84,6 +84,8 @@ struct nfsd_net {
        struct list_head client_lru;
        struct list_head close_lru;
        struct list_head del_recall_lru;
+
+       /* protected by blocked_locks_lock */
        struct list_head blocked_locks_lru;
 
        struct delayed_work laundromat_work;
@@ -91,6 +93,9 @@ struct nfsd_net {
        /* client_lock protects the client lru list and session hash table */
        spinlock_t client_lock;
 
+       /* protects blocked_locks_lru */
+       spinlock_t blocked_locks_lock;
+
        struct file *rec_file;
        bool in_grace;
        const struct nfsd4_client_tracking_ops *client_tracking_ops;
index 9752beb78659dd1f02a4411a397fb27b9a8cf4ef..4b4beaaa4eaac01233f874c7dfdb8d1a6d7cd3d6 100644 (file)
@@ -217,7 +217,7 @@ find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
 {
        struct nfsd4_blocked_lock *cur, *found = NULL;
 
-       spin_lock(&nn->client_lock);
+       spin_lock(&nn->blocked_locks_lock);
        list_for_each_entry(cur, &lo->lo_blocked, nbl_list) {
                if (fh_match(fh, &cur->nbl_fh)) {
                        list_del_init(&cur->nbl_list);
@@ -226,7 +226,7 @@ find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh,
                        break;
                }
        }
-       spin_unlock(&nn->client_lock);
+       spin_unlock(&nn->blocked_locks_lock);
        if (found)
                posix_unblock_lock(&found->nbl_lock);
        return found;
@@ -1227,9 +1227,7 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
 
 static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
 {
-       struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
-
-       lockdep_assert_held(&oo->oo_owner.so_client->cl_lock);
+       lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
 
        list_del_init(&stp->st_locks);
        nfs4_unhash_stid(&stp->st_stid);
@@ -1238,12 +1236,12 @@ static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
 
 static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 {
-       struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
+       struct nfs4_client *clp = stp->st_stid.sc_client;
        bool unhashed;
 
-       spin_lock(&oo->oo_owner.so_client->cl_lock);
+       spin_lock(&clp->cl_lock);
        unhashed = unhash_lock_stateid(stp);
-       spin_unlock(&oo->oo_owner.so_client->cl_lock);
+       spin_unlock(&clp->cl_lock);
        if (unhashed)
                nfs4_put_stid(&stp->st_stid);
 }
@@ -4665,7 +4663,7 @@ nfs4_laundromat(struct nfsd_net *nn)
         * indefinitely once the lock does become free.
         */
        BUG_ON(!list_empty(&reaplist));
-       spin_lock(&nn->client_lock);
+       spin_lock(&nn->blocked_locks_lock);
        while (!list_empty(&nn->blocked_locks_lru)) {
                nbl = list_first_entry(&nn->blocked_locks_lru,
                                        struct nfsd4_blocked_lock, nbl_lru);
@@ -4678,7 +4676,7 @@ nfs4_laundromat(struct nfsd_net *nn)
                list_move(&nbl->nbl_lru, &reaplist);
                list_del_init(&nbl->nbl_list);
        }
-       spin_unlock(&nn->client_lock);
+       spin_unlock(&nn->blocked_locks_lock);
 
        while (!list_empty(&reaplist)) {
                nbl = list_first_entry(&nn->blocked_locks_lru,
@@ -5439,13 +5437,13 @@ nfsd4_lm_notify(struct file_lock *fl)
        bool queue = false;
 
        /* An empty list means that something else is going to be using it */
-       spin_lock(&nn->client_lock);
+       spin_lock(&nn->blocked_locks_lock);
        if (!list_empty(&nbl->nbl_list)) {
                list_del_init(&nbl->nbl_list);
                list_del_init(&nbl->nbl_lru);
                queue = true;
        }
-       spin_unlock(&nn->client_lock);
+       spin_unlock(&nn->blocked_locks_lock);
 
        if (queue)
                nfsd4_run_cb(&nbl->nbl_cb);
@@ -5868,10 +5866,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        if (fl_flags & FL_SLEEP) {
                nbl->nbl_time = jiffies;
-               spin_lock(&nn->client_lock);
+               spin_lock(&nn->blocked_locks_lock);
                list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked);
                list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru);
-               spin_unlock(&nn->client_lock);
+               spin_unlock(&nn->blocked_locks_lock);
        }
 
        err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
@@ -5900,10 +5898,10 @@ out:
        if (nbl) {
                /* dequeue it if we queued it before */
                if (fl_flags & FL_SLEEP) {
-                       spin_lock(&nn->client_lock);
+                       spin_lock(&nn->blocked_locks_lock);
                        list_del_init(&nbl->nbl_list);
                        list_del_init(&nbl->nbl_lru);
-                       spin_unlock(&nn->client_lock);
+                       spin_unlock(&nn->blocked_locks_lock);
                }
                free_blocked_lock(nbl);
        }
@@ -6943,9 +6941,11 @@ static int nfs4_state_create_net(struct net *net)
        INIT_LIST_HEAD(&nn->client_lru);
        INIT_LIST_HEAD(&nn->close_lru);
        INIT_LIST_HEAD(&nn->del_recall_lru);
-       INIT_LIST_HEAD(&nn->blocked_locks_lru);
        spin_lock_init(&nn->client_lock);
 
+       spin_lock_init(&nn->blocked_locks_lock);
+       INIT_LIST_HEAD(&nn->blocked_locks_lru);
+
        INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
        get_net(net);
 
@@ -7063,14 +7063,14 @@ nfs4_state_shutdown_net(struct net *net)
        }
 
        BUG_ON(!list_empty(&reaplist));
-       spin_lock(&nn->client_lock);
+       spin_lock(&nn->blocked_locks_lock);
        while (!list_empty(&nn->blocked_locks_lru)) {
                nbl = list_first_entry(&nn->blocked_locks_lru,
                                        struct nfsd4_blocked_lock, nbl_lru);
                list_move(&nbl->nbl_lru, &reaplist);
                list_del_init(&nbl->nbl_list);
        }
-       spin_unlock(&nn->client_lock);
+       spin_unlock(&nn->blocked_locks_lock);
 
        while (!list_empty(&reaplist)) {
                nbl = list_first_entry(&nn->blocked_locks_lru,
index a1861357900127e19182932c39322c55d17fe5fe..0ee19ecc982d4e4ef8137836ba4d753559eb7612 100644 (file)
@@ -1544,8 +1544,6 @@ const struct file_operations ntfs_dir_ops = {
        .iterate        = ntfs_readdir,         /* Read directory contents. */
 #ifdef NTFS_RW
        .fsync          = ntfs_dir_fsync,       /* Sync a directory to disk. */
-       /*.aio_fsync    = ,*/                   /* Sync all outstanding async
-                                                  i/o operations on a kiocb. */
 #endif /* NTFS_RW */
        /*.ioctl        = ,*/                   /* Perform function on the
                                                   mounted filesystem. */
index e7054e2ac9227dc4687a98beea6e005c2d03d988..3ecb9f337b7d318868ad1c1ebaaf7ea331aeb623 100644 (file)
@@ -3699,7 +3699,7 @@ static void ocfs2_dx_dir_transfer_leaf(struct inode *dir, u32 split_hash,
 static int ocfs2_dx_dir_rebalance_credits(struct ocfs2_super *osb,
                                          struct ocfs2_dx_root_block *dx_root)
 {
-       int credits = ocfs2_clusters_to_blocks(osb->sb, 2);
+       int credits = ocfs2_clusters_to_blocks(osb->sb, 3);
 
        credits += ocfs2_calc_extend_credits(osb->sb, &dx_root->dr_list);
        credits += ocfs2_quota_trans_credits(osb->sb);
index 1e8fe844e69fdaa92c80c9ca162d736c8b06a984..5355efba4bc8c13f4e2ac2f5a7dfe7a6a6284225 100644 (file)
@@ -73,7 +73,7 @@ static int orangefs_revalidate_lookup(struct dentry *dentry)
                }
        }
 
-       dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
+       orangefs_set_timeout(dentry);
        ret = 1;
 out_release_op:
        op_release(new_op);
@@ -94,8 +94,9 @@ out_drop:
 static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        int ret;
+       unsigned long time = (unsigned long) dentry->d_fsdata;
 
-       if (time_before(jiffies, dentry->d_time))
+       if (time_before(jiffies, time))
                return 1;
 
        if (flags & LOOKUP_RCU)
index 66ea0cc37b189fc0b129606ef9893cc68a4b6d43..02cc6139ec90798900f6c626934c9f6d2baee266 100644 (file)
@@ -621,9 +621,9 @@ static int orangefs_file_release(struct inode *inode, struct file *file)
         * readahead cache (if any); this forces an expensive refresh of
         * data for the next caller of mmap (or 'get_block' accesses)
         */
-       if (file->f_path.dentry->d_inode &&
-           file->f_path.dentry->d_inode->i_mapping &&
-           mapping_nrpages(&file->f_path.dentry->d_inode->i_data)) {
+       if (file_inode(file) &&
+           file_inode(file)->i_mapping &&
+           mapping_nrpages(&file_inode(file)->i_data)) {
                if (orangefs_features & ORANGEFS_FEATURE_READAHEAD) {
                        gossip_debug(GOSSIP_INODE_DEBUG,
                            "calling flush_racache on %pU\n",
@@ -632,7 +632,7 @@ static int orangefs_file_release(struct inode *inode, struct file *file)
                        gossip_debug(GOSSIP_INODE_DEBUG,
                            "flush_racache finished\n");
                }
-               truncate_inode_pages(file->f_path.dentry->d_inode->i_mapping,
+               truncate_inode_pages(file_inode(file)->i_mapping,
                                     0);
        }
        return 0;
@@ -648,7 +648,7 @@ static int orangefs_fsync(struct file *file,
 {
        int ret = -EINVAL;
        struct orangefs_inode_s *orangefs_inode =
-               ORANGEFS_I(file->f_path.dentry->d_inode);
+               ORANGEFS_I(file_inode(file));
        struct orangefs_kernel_op_s *new_op = NULL;
 
        /* required call */
@@ -661,7 +661,7 @@ static int orangefs_fsync(struct file *file,
 
        ret = service_operation(new_op,
                        "orangefs_fsync",
-                       get_interruptible_flag(file->f_path.dentry->d_inode));
+                       get_interruptible_flag(file_inode(file)));
 
        gossip_debug(GOSSIP_FILE_DEBUG,
                     "orangefs_fsync got return value of %d\n",
@@ -669,7 +669,7 @@ static int orangefs_fsync(struct file *file,
 
        op_release(new_op);
 
-       orangefs_flush_inode(file->f_path.dentry->d_inode);
+       orangefs_flush_inode(file_inode(file));
        return ret;
 }
 
index d15d3d2dba6225ce52bf97127a2de62dae609b8d..a290ff6ec7569dc3b5eea9ded2df0e8483c49d65 100644 (file)
@@ -72,7 +72,7 @@ static int orangefs_create(struct inode *dir,
 
        d_instantiate(dentry, inode);
        unlock_new_inode(inode);
-       dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
+       orangefs_set_timeout(dentry);
        ORANGEFS_I(inode)->getattr_time = jiffies - 1;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
@@ -183,7 +183,7 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
                goto out;
        }
 
-       dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
+       orangefs_set_timeout(dentry);
 
        inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
        if (IS_ERR(inode)) {
@@ -322,7 +322,7 @@ static int orangefs_symlink(struct inode *dir,
 
        d_instantiate(dentry, inode);
        unlock_new_inode(inode);
-       dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
+       orangefs_set_timeout(dentry);
        ORANGEFS_I(inode)->getattr_time = jiffies - 1;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
@@ -386,7 +386,7 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
 
        d_instantiate(dentry, inode);
        unlock_new_inode(inode);
-       dentry->d_time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
+       orangefs_set_timeout(dentry);
        ORANGEFS_I(inode)->getattr_time = jiffies - 1;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
index eb09aa026723820099a91ed4563caff0e22b8512..38887cc5577fa901acd907a0af2fb016a3441b2c 100644 (file)
@@ -114,6 +114,7 @@ static const struct seq_operations help_debug_ops = {
 };
 
 const struct file_operations debug_help_fops = {
+       .owner          = THIS_MODULE,
        .open           = orangefs_debug_help_open,
        .read           = seq_read,
        .release        = seq_release,
@@ -121,6 +122,7 @@ const struct file_operations debug_help_fops = {
 };
 
 static const struct file_operations kernel_debug_fops = {
+       .owner          = THIS_MODULE,
        .open           = orangefs_debug_open,
        .read           = orangefs_debug_read,
        .write          = orangefs_debug_write,
@@ -141,6 +143,9 @@ static struct client_debug_mask client_debug_mask;
  */
 static DEFINE_MUTEX(orangefs_debug_lock);
 
+/* Used to protect data in ORANGEFS_KMOD_DEBUG_HELP_FILE */
+static DEFINE_MUTEX(orangefs_help_file_lock);
+
 /*
  * initialize kmod debug operations, create orangefs debugfs dir and
  * ORANGEFS_KMOD_DEBUG_HELP_FILE.
@@ -289,6 +294,8 @@ static void *help_start(struct seq_file *m, loff_t *pos)
 
        gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n");
 
+       mutex_lock(&orangefs_help_file_lock);
+
        if (*pos == 0)
                payload = m->private;
 
@@ -305,6 +312,7 @@ static void *help_next(struct seq_file *m, void *v, loff_t *pos)
 static void help_stop(struct seq_file *m, void *p)
 {
        gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n");
+       mutex_unlock(&orangefs_help_file_lock);
 }
 
 static int help_show(struct seq_file *m, void *v)
@@ -610,32 +618,54 @@ out:
  * /sys/kernel/debug/orangefs/debug-help can be catted to
  * see all the available kernel and client debug keywords.
  *
- * When the kernel boots, we have no idea what keywords the
+ * When orangefs.ko initializes, we have no idea what keywords the
  * client supports, nor their associated masks.
  *
- * We pass through this function once at boot and stamp a
+ * We pass through this function once at module-load and stamp a
  * boilerplate "we don't know" message for the client in the
  * debug-help file. We pass through here again when the client
  * starts and then we can fill out the debug-help file fully.
  *
  * The client might be restarted any number of times between
- * reboots, we only build the debug-help file the first time.
+ * module reloads, we only build the debug-help file the first time.
  */
 int orangefs_prepare_debugfs_help_string(int at_boot)
 {
-       int rc = -EINVAL;
-       int i;
-       int byte_count = 0;
        char *client_title = "Client Debug Keywords:\n";
        char *kernel_title = "Kernel Debug Keywords:\n";
+       size_t string_size =  DEBUG_HELP_STRING_SIZE;
+       size_t result_size;
+       size_t i;
+       char *new;
+       int rc = -EINVAL;
 
        gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
 
-       if (at_boot) {
-               byte_count += strlen(HELP_STRING_UNINITIALIZED);
+       if (at_boot)
                client_title = HELP_STRING_UNINITIALIZED;
-       } else {
-               /*
+
+       /* build a new debug_help_string. */
+       new = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL);
+       if (!new) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * strlcat(dst, src, size) will append at most
+        * "size - strlen(dst) - 1" bytes of src onto dst,
+        * null terminating the result, and return the total
+        * length of the string it tried to create.
+        *
+        * We'll just plow through here building our new debug
+        * help string and let strlcat take care of assuring that
+        * dst doesn't overflow.
+        */
+       strlcat(new, client_title, string_size);
+
+       if (!at_boot) {
+
+                /*
                 * fill the client keyword/mask array and remember
                 * how many elements there were.
                 */
@@ -644,64 +674,40 @@ int orangefs_prepare_debugfs_help_string(int at_boot)
                if (cdm_element_count <= 0)
                        goto out;
 
-               /* Count the bytes destined for debug_help_string. */
-               byte_count += strlen(client_title);
-
                for (i = 0; i < cdm_element_count; i++) {
-                       byte_count += strlen(cdm_array[i].keyword + 2);
-                       if (byte_count >= DEBUG_HELP_STRING_SIZE) {
-                               pr_info("%s: overflow 1!\n", __func__);
-                               goto out;
-                       }
+                       strlcat(new, "\t", string_size);
+                       strlcat(new, cdm_array[i].keyword, string_size);
+                       strlcat(new, "\n", string_size);
                }
-
-               gossip_debug(GOSSIP_UTILS_DEBUG,
-                            "%s: cdm_element_count:%d:\n",
-                            __func__,
-                            cdm_element_count);
        }
 
-       byte_count += strlen(kernel_title);
+       strlcat(new, "\n", string_size);
+       strlcat(new, kernel_title, string_size);
+
        for (i = 0; i < num_kmod_keyword_mask_map; i++) {
-               byte_count +=
-                       strlen(s_kmod_keyword_mask_map[i].keyword + 2);
-               if (byte_count >= DEBUG_HELP_STRING_SIZE) {
-                       pr_info("%s: overflow 2!\n", __func__);
-                       goto out;
-               }
+               strlcat(new, "\t", string_size);
+               strlcat(new, s_kmod_keyword_mask_map[i].keyword, string_size);
+               result_size = strlcat(new, "\n", string_size);
        }
 
-       /* build debug_help_string. */
-       debug_help_string = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL);
-       if (!debug_help_string) {
-               rc = -ENOMEM;
+       /* See if we tried to put too many bytes into "new"... */
+       if (result_size >= string_size) {
+               kfree(new);
                goto out;
        }
 
-       strcat(debug_help_string, client_title);
-
-       if (!at_boot) {
-               for (i = 0; i < cdm_element_count; i++) {
-                       strcat(debug_help_string, "\t");
-                       strcat(debug_help_string, cdm_array[i].keyword);
-                       strcat(debug_help_string, "\n");
-               }
-       }
-
-       strcat(debug_help_string, "\n");
-       strcat(debug_help_string, kernel_title);
-
-       for (i = 0; i < num_kmod_keyword_mask_map; i++) {
-               strcat(debug_help_string, "\t");
-               strcat(debug_help_string, s_kmod_keyword_mask_map[i].keyword);
-               strcat(debug_help_string, "\n");
+       if (at_boot) {
+               debug_help_string = new;
+       } else {
+               mutex_lock(&orangefs_help_file_lock);
+               memset(debug_help_string, 0, DEBUG_HELP_STRING_SIZE);
+               strlcat(debug_help_string, new, string_size);
+               mutex_unlock(&orangefs_help_file_lock);
        }
 
        rc = 0;
 
-out:
-
-       return rc;
+out:   return rc;
 
 }
 
@@ -959,8 +965,12 @@ int orangefs_debugfs_new_client_string(void __user *arg)
        ret = copy_from_user(&client_debug_array_string,
                                      (void __user *)arg,
                                      ORANGEFS_MAX_DEBUG_STRING_LEN);
-       if (ret != 0)
+
+       if (ret != 0) {
+               pr_info("%s: CLIENT_STRING: copy_from_user failed\n",
+                       __func__);
                return -EIO;
+       }
 
        /*
         * The real client-core makes an effort to ensure
@@ -975,45 +985,18 @@ int orangefs_debugfs_new_client_string(void __user *arg)
        client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN - 1] =
                '\0';
        
-       if (ret != 0) {
-               pr_info("%s: CLIENT_STRING: copy_from_user failed\n",
-                       __func__);
-               return -EIO;
-       }
-
        pr_info("%s: client debug array string has been received.\n",
                __func__);
 
        if (!help_string_initialized) {
 
-               /* Free the "we don't know yet" default string... */
-               kfree(debug_help_string);
-
-               /* build a proper debug help string */
+               /* Build a proper debug help string. */
                if (orangefs_prepare_debugfs_help_string(0)) {
                        gossip_err("%s: no debug help string \n",
                                   __func__);
                        return -EIO;
                }
 
-               /* Replace the boilerplate boot-time debug-help file. */
-               debugfs_remove(help_file_dentry);
-
-               help_file_dentry =
-                       debugfs_create_file(
-                               ORANGEFS_KMOD_DEBUG_HELP_FILE,
-                               0444,
-                               debug_dir,
-                               debug_help_string,
-                               &debug_help_fops);
-
-               if (!help_file_dentry) {
-                       gossip_err("%s: debugfs_create_file failed for"
-                                  " :%s:!\n",
-                                  __func__,
-                                  ORANGEFS_KMOD_DEBUG_HELP_FILE);
-                       return -EIO;
-               }
        }
 
        debug_mask_to_string(&client_debug_mask, 1);
index 0a82048f3aafadbc3b8195acba3a877ed65f2a0d..3bf803d732c5b3702f735c5776cae6d249b85364 100644 (file)
@@ -580,4 +580,11 @@ static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size)
 #endif
 }
 
+static inline void orangefs_set_timeout(struct dentry *dentry)
+{
+       unsigned long time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
+
+       dentry->d_fsdata = (void *) time;
+}
+
 #endif /* __ORANGEFSKERNEL_H */
index 2e5b03065f345a3e9f48d0401f0def348eeaa1e6..4113eb0495bf90549daca478dd0f8c5a7940680a 100644 (file)
@@ -124,7 +124,7 @@ static int __init orangefs_init(void)
         * unknown at boot time.
         *
         * orangefs_prepare_debugfs_help_string will be used again
-        * later to rebuild the debug-help file after the client starts
+        * later to rebuild the debug-help-string after the client starts
         * and passes along the needed info. The argument signifies
         * which time orangefs_prepare_debugfs_help_string is being
         * called.
@@ -152,7 +152,9 @@ static int __init orangefs_init(void)
 
        ret = register_filesystem(&orangefs_fs_type);
        if (ret == 0) {
-               pr_info("orangefs: module version %s loaded\n", ORANGEFS_VERSION);
+               pr_info("%s: module version %s loaded\n",
+                       __func__,
+                       ORANGEFS_VERSION);
                ret = 0;
                goto out;
        }
index aeb60f791418d6d6cba59f2dc743e8b8c71d5297..36795eed40b09ee1bbb6766e65019b8d1c6695f0 100644 (file)
@@ -178,6 +178,8 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
                len -= bytes;
        }
 
+       if (!error)
+               error = vfs_fsync(new_file, 0);
        fput(new_file);
 out_fput:
        fput(old_file);
index c58f01babf30e7ecbfe86ab0862a8c8171734866..7fb53d05553780ac4bc9f3909afdb81df723af32 100644 (file)
@@ -270,9 +270,6 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type)
        if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode))
                return NULL;
 
-       if (!realinode->i_op->get_acl)
-               return NULL;
-
        old_cred = ovl_override_creds(inode->i_sb);
        acl = get_acl(realinode, type);
        revert_creds(old_cred);
index bcf3965be81942415c404b1253bfd59f809c0100..0e100856c7b8c252b4555b14747197fb6ee5303a 100644 (file)
@@ -328,11 +328,11 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
        if (!real)
                goto bug;
 
+       /* Handle recursion */
+       real = d_real(real, inode, open_flags);
+
        if (!inode || inode == d_inode(real))
                return real;
-
-       /* Handle recursion */
-       return d_real(real, inode, open_flags);
 bug:
        WARN(1, "ovl_d_real(%pd4, %s:%lu): real dentry not found\n", dentry,
             inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);
@@ -1037,6 +1037,21 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
 
        posix_acl_release(acl);
 
+       /*
+        * Check if sgid bit needs to be cleared (actual setacl operation will
+        * be done with mounter's capabilities and so that won't do it for us).
+        */
+       if (unlikely(inode->i_mode & S_ISGID) &&
+           handler->flags == ACL_TYPE_ACCESS &&
+           !in_group_p(inode->i_gid) &&
+           !capable_wrt_inode_uidgid(inode, CAP_FSETID)) {
+               struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
+
+               err = ovl_setattr(dentry, &iattr);
+               if (err)
+                       return err;
+       }
+
        err = ovl_xattr_set(dentry, handler->name, value, size, flags);
        if (!err)
                ovl_copyattr(ovl_inode_real(inode, NULL), inode);
index 89600fd5963d46d5a5bd0915bde36850f7e71110..81818adb8e9ee3cc1adfbd5d0487d427f8c1f531 100644 (file)
@@ -412,10 +412,11 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
        mm = get_task_mm(task);
        if (mm) {
                vsize = task_vsize(mm);
-               if (permitted) {
-                       eip = KSTK_EIP(task);
-                       esp = KSTK_ESP(task);
-               }
+               /*
+                * esp and eip are intentionally zeroed out.  There is no
+                * non-racy way to read them without freezing the task.
+                * Programs that need reliable values can use ptrace(2).
+                */
        }
 
        get_task_comm(tcomm, task);
index c2964d890c9a58910d4d9c2b53c5845637fed70e..ca651ac00660889a86fcd5c27d4a29aa709d5a53 100644 (file)
@@ -832,6 +832,7 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
        unsigned long addr = *ppos;
        ssize_t copied;
        char *page;
+       unsigned int flags;
 
        if (!mm)
                return 0;
@@ -844,6 +845,11 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
        if (!atomic_inc_not_zero(&mm->mm_users))
                goto free;
 
+       /* Maybe we should limit FOLL_FORCE to actual ptrace users? */
+       flags = FOLL_FORCE;
+       if (write)
+               flags |= FOLL_WRITE;
+
        while (count > 0) {
                int this_len = min_t(int, count, PAGE_SIZE);
 
@@ -852,7 +858,7 @@ static ssize_t mem_rw(struct file *file, char __user *buf,
                        break;
                }
 
-               this_len = access_remote_vm(mm, addr, page, this_len, write);
+               this_len = access_remote_vm(mm, addr, page, this_len, flags);
                if (!this_len) {
                        if (!copied)
                                copied = -EIO;
@@ -964,8 +970,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,
                max_len = min_t(size_t, PAGE_SIZE, count);
                this_len = min(max_len, this_len);
 
-               retval = access_remote_vm(mm, (env_start + src),
-                       page, this_len, 0);
+               retval = access_remote_vm(mm, (env_start + src), page, this_len, 0);
 
                if (retval <= 0) {
                        ret = retval;
@@ -1007,6 +1012,9 @@ static ssize_t auxv_read(struct file *file, char __user *buf,
 {
        struct mm_struct *mm = file->private_data;
        unsigned int nwords = 0;
+
+       if (!mm)
+               return 0;
        do {
                nwords += 2;
        } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */
index 6909582ce5e5b9f6d94a89a4e1eb184488c0518e..35b92d81692f098efc911cbdd334182a96c546a8 100644 (file)
@@ -266,24 +266,15 @@ static int do_maps_open(struct inode *inode, struct file *file,
  * /proc/PID/maps that is the stack of the main task.
  */
 static int is_stack(struct proc_maps_private *priv,
-                   struct vm_area_struct *vma, int is_pid)
+                   struct vm_area_struct *vma)
 {
-       int stack = 0;
-
-       if (is_pid) {
-               stack = vma->vm_start <= vma->vm_mm->start_stack &&
-                       vma->vm_end >= vma->vm_mm->start_stack;
-       } else {
-               struct inode *inode = priv->inode;
-               struct task_struct *task;
-
-               rcu_read_lock();
-               task = pid_task(proc_pid(inode), PIDTYPE_PID);
-               if (task)
-                       stack = vma_is_stack_for_task(vma, task);
-               rcu_read_unlock();
-       }
-       return stack;
+       /*
+        * We make no effort to guess what a given thread considers to be
+        * its "stack".  It's not even well-defined for programs written
+        * languages like Go.
+        */
+       return vma->vm_start <= vma->vm_mm->start_stack &&
+               vma->vm_end >= vma->vm_mm->start_stack;
 }
 
 static void
@@ -354,7 +345,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
                        goto done;
                }
 
-               if (is_stack(priv, vma, is_pid))
+               if (is_stack(priv, vma))
                        name = "[stack]";
        }
 
@@ -1669,7 +1660,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
                seq_file_path(m, file, "\n\t= ");
        } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
                seq_puts(m, " heap");
-       } else if (is_stack(proc_priv, vma, is_pid)) {
+       } else if (is_stack(proc_priv, vma)) {
                seq_puts(m, " stack");
        }
 
index faacb0c0d857602111bfc04f2e374c451059c358..37175621e8906881adf4e034ce06224664120031 100644 (file)
@@ -124,25 +124,17 @@ unsigned long task_statm(struct mm_struct *mm,
 }
 
 static int is_stack(struct proc_maps_private *priv,
-                   struct vm_area_struct *vma, int is_pid)
+                   struct vm_area_struct *vma)
 {
        struct mm_struct *mm = vma->vm_mm;
-       int stack = 0;
-
-       if (is_pid) {
-               stack = vma->vm_start <= mm->start_stack &&
-                       vma->vm_end >= mm->start_stack;
-       } else {
-               struct inode *inode = priv->inode;
-               struct task_struct *task;
-
-               rcu_read_lock();
-               task = pid_task(proc_pid(inode), PIDTYPE_PID);
-               if (task)
-                       stack = vma_is_stack_for_task(vma, task);
-               rcu_read_unlock();
-       }
-       return stack;
+
+       /*
+        * We make no effort to guess what a given thread considers to be
+        * its "stack".  It's not even well-defined for programs written
+        * languages like Go.
+        */
+       return vma->vm_start <= mm->start_stack &&
+               vma->vm_end >= mm->start_stack;
 }
 
 /*
@@ -184,7 +176,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
        if (file) {
                seq_pad(m, ' ');
                seq_file_path(m, file, "");
-       } else if (mm && is_stack(priv, vma, is_pid)) {
+       } else if (mm && is_stack(priv, vma)) {
                seq_pad(m, ' ');
                seq_printf(m, "[stack]");
        }
index 153d4f3bd441febd7004b1862cd218afc0ee6252..5a7750bd2eea765d06f5e8b76687701b24867c7b 100644 (file)
@@ -299,13 +299,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
 {
        struct iov_iter to;
        struct kiocb kiocb;
-       loff_t isize;
        int idx, ret;
 
-       isize = i_size_read(in->f_mapping->host);
-       if (unlikely(*ppos >= isize))
-               return 0;
-
        iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len);
        idx = to.idx;
        init_sync_kiocb(&kiocb, in);
@@ -413,7 +408,8 @@ static ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
        if (res <= 0)
                return -ENOMEM;
 
-       nr_pages = res / PAGE_SIZE;
+       BUG_ON(dummy);
+       nr_pages = DIV_ROUND_UP(res, PAGE_SIZE);
 
        vec = __vec;
        if (nr_pages > PIPE_DEF_BUFFERS) {
index c8f60df2733eba516b189716a6b3bb3ab64520d1..ca16c5d7bab1726af305fa3a1a534ab5bc78cb4e 100644 (file)
@@ -439,7 +439,7 @@ static unsigned int vfs_dent_type(uint8_t type)
  */
 static int ubifs_readdir(struct file *file, struct dir_context *ctx)
 {
-       int err;
+       int err = 0;
        struct qstr nm;
        union ubifs_key key;
        struct ubifs_dent_node *dent;
@@ -541,14 +541,20 @@ out:
        kfree(file->private_data);
        file->private_data = NULL;
 
-       if (err != -ENOENT) {
+       if (err != -ENOENT)
                ubifs_err(c, "cannot find next direntry, error %d", err);
-               return err;
-       }
+       else
+               /*
+                * -ENOENT is a non-fatal error in this context, the TNC uses
+                * it to indicate that the cursor moved past the current directory
+                * and readdir() has to stop.
+                */
+               err = 0;
+
 
        /* 2 is a special value indicating that there are no more direntries */
        ctx->pos = 2;
-       return 0;
+       return err;
 }
 
 /* Free saved readdir() state when the directory is closed */
@@ -1060,9 +1066,9 @@ static void unlock_4_inodes(struct inode *inode1, struct inode *inode2,
        mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
 }
 
-static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
-                       struct inode *new_dir, struct dentry *new_dentry,
-                       unsigned int flags)
+static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
+                    struct inode *new_dir, struct dentry *new_dentry,
+                    unsigned int flags)
 {
        struct ubifs_info *c = old_dir->i_sb->s_fs_info;
        struct inode *old_inode = d_inode(old_dentry);
@@ -1323,7 +1329,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
        return err;
 }
 
-static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry,
+static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        struct inode *new_dir, struct dentry *new_dentry,
                        unsigned int flags)
 {
@@ -1336,7 +1342,7 @@ static int ubifs_rename2(struct inode *old_dir, struct dentry *old_dentry,
        if (flags & RENAME_EXCHANGE)
                return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry);
 
-       return ubifs_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
+       return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
 }
 
 int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -1387,7 +1393,7 @@ const struct inode_operations ubifs_dir_inode_operations = {
        .mkdir       = ubifs_mkdir,
        .rmdir       = ubifs_rmdir,
        .mknod       = ubifs_mknod,
-       .rename      = ubifs_rename2,
+       .rename      = ubifs_rename,
        .setattr     = ubifs_setattr,
        .getattr     = ubifs_getattr,
        .listxattr   = ubifs_listxattr,
index 6c2f4d41ed737c0bf90482a8674ea1a29948fca4..d9f9615bfd71a24c4235795cef11f7c5b1c4c6b6 100644 (file)
@@ -172,6 +172,7 @@ out_cancel:
        host_ui->xattr_cnt -= 1;
        host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
        host_ui->xattr_size -= CALC_XATTR_BYTES(size);
+       host_ui->xattr_names -= nm->len;
        mutex_unlock(&host_ui->ui_mutex);
 out_free:
        make_bad_inode(inode);
@@ -478,6 +479,7 @@ out_cancel:
        host_ui->xattr_cnt += 1;
        host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
        host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
+       host_ui->xattr_names += nm->len;
        mutex_unlock(&host_ui->ui_mutex);
        ubifs_release_budget(c, &req);
        make_bad_inode(inode);
index 3368659c471e4f7dc8cd425738bccb7d5fec78a6..2d13b4e62faec1cd0e3ff8d5966e767821867a2c 100644 (file)
@@ -170,7 +170,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
                const void *value, size_t size, int flags)
 {
        struct inode *inode = dentry->d_inode;
-       int error = -EOPNOTSUPP;
+       int error = -EAGAIN;
        int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
                                   XATTR_SECURITY_PREFIX_LEN);
 
@@ -183,15 +183,21 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
                        security_inode_post_setxattr(dentry, name, value,
                                                     size, flags);
                }
-       } else if (issec) {
-               const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
-
+       } else {
                if (unlikely(is_bad_inode(inode)))
                        return -EIO;
-               error = security_inode_setsecurity(inode, suffix, value,
-                                                  size, flags);
-               if (!error)
-                       fsnotify_xattr(dentry);
+       }
+       if (error == -EAGAIN) {
+               error = -EOPNOTSUPP;
+
+               if (issec) {
+                       const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
+
+                       error = security_inode_setsecurity(inode, suffix, value,
+                                                          size, flags);
+                       if (!error)
+                               fsnotify_xattr(dentry);
+               }
        }
 
        return error;
index c27344cf38e177187f048eb799297f281eea5a2f..c6eb21940783e4de3c555520eddbba48d0b19be4 100644 (file)
@@ -3974,9 +3974,6 @@ xfs_bmap_remap_alloc(
         * allocating, so skip that check by pretending to be freeing.
         */
        error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
-       if (error)
-               goto error0;
-error0:
        xfs_perag_put(args.pag);
        if (error)
                trace_xfs_bmap_remap_alloc_error(ap->ip, error, _RET_IP_);
@@ -3999,6 +3996,39 @@ xfs_bmap_alloc(
        return xfs_bmap_btalloc(ap);
 }
 
+/* Trim extent to fit a logical block range. */
+void
+xfs_trim_extent(
+       struct xfs_bmbt_irec    *irec,
+       xfs_fileoff_t           bno,
+       xfs_filblks_t           len)
+{
+       xfs_fileoff_t           distance;
+       xfs_fileoff_t           end = bno + len;
+
+       if (irec->br_startoff + irec->br_blockcount <= bno ||
+           irec->br_startoff >= end) {
+               irec->br_blockcount = 0;
+               return;
+       }
+
+       if (irec->br_startoff < bno) {
+               distance = bno - irec->br_startoff;
+               if (isnullstartblock(irec->br_startblock))
+                       irec->br_startblock = DELAYSTARTBLOCK;
+               if (irec->br_startblock != DELAYSTARTBLOCK &&
+                   irec->br_startblock != HOLESTARTBLOCK)
+                       irec->br_startblock += distance;
+               irec->br_startoff += distance;
+               irec->br_blockcount -= distance;
+       }
+
+       if (end < irec->br_startoff + irec->br_blockcount) {
+               distance = irec->br_startoff + irec->br_blockcount - end;
+               irec->br_blockcount -= distance;
+       }
+}
+
 /*
  * Trim the returned map to the required bounds
  */
@@ -4829,6 +4859,219 @@ xfs_bmap_split_indlen(
        return stolen;
 }
 
+int
+xfs_bmap_del_extent_delay(
+       struct xfs_inode        *ip,
+       int                     whichfork,
+       xfs_extnum_t            *idx,
+       struct xfs_bmbt_irec    *got,
+       struct xfs_bmbt_irec    *del)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_bmbt_irec    new;
+       int64_t                 da_old, da_new, da_diff = 0;
+       xfs_fileoff_t           del_endoff, got_endoff;
+       xfs_filblks_t           got_indlen, new_indlen, stolen;
+       int                     error = 0, state = 0;
+       bool                    isrt;
+
+       XFS_STATS_INC(mp, xs_del_exlist);
+
+       isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
+       del_endoff = del->br_startoff + del->br_blockcount;
+       got_endoff = got->br_startoff + got->br_blockcount;
+       da_old = startblockval(got->br_startblock);
+       da_new = 0;
+
+       ASSERT(*idx >= 0);
+       ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
+       ASSERT(del->br_blockcount > 0);
+       ASSERT(got->br_startoff <= del->br_startoff);
+       ASSERT(got_endoff >= del_endoff);
+
+       if (isrt) {
+               int64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount);
+
+               do_div(rtexts, mp->m_sb.sb_rextsize);
+               xfs_mod_frextents(mp, rtexts);
+       }
+
+       /*
+        * Update the inode delalloc counter now and wait to update the
+        * sb counters as we might have to borrow some blocks for the
+        * indirect block accounting.
+        */
+       xfs_trans_reserve_quota_nblks(NULL, ip, -((long)del->br_blockcount), 0,
+                       isrt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
+       ip->i_delayed_blks -= del->br_blockcount;
+
+       if (whichfork == XFS_COW_FORK)
+               state |= BMAP_COWFORK;
+
+       if (got->br_startoff == del->br_startoff)
+               state |= BMAP_LEFT_CONTIG;
+       if (got_endoff == del_endoff)
+               state |= BMAP_RIGHT_CONTIG;
+
+       switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) {
+       case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
+               /*
+                * Matches the whole extent.  Delete the entry.
+                */
+               xfs_iext_remove(ip, *idx, 1, state);
+               --*idx;
+               break;
+       case BMAP_LEFT_CONTIG:
+               /*
+                * Deleting the first part of the extent.
+                */
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               got->br_startoff = del_endoff;
+               got->br_blockcount -= del->br_blockcount;
+               da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip,
+                               got->br_blockcount), da_old);
+               got->br_startblock = nullstartblock((int)da_new);
+               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               break;
+       case BMAP_RIGHT_CONTIG:
+               /*
+                * Deleting the last part of the extent.
+                */
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               got->br_blockcount = got->br_blockcount - del->br_blockcount;
+               da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip,
+                               got->br_blockcount), da_old);
+               got->br_startblock = nullstartblock((int)da_new);
+               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               break;
+       case 0:
+               /*
+                * Deleting the middle of the extent.
+                *
+                * Distribute the original indlen reservation across the two new
+                * extents.  Steal blocks from the deleted extent if necessary.
+                * Stealing blocks simply fudges the fdblocks accounting below.
+                * Warn if either of the new indlen reservations is zero as this
+                * can lead to delalloc problems.
+                */
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+
+               got->br_blockcount = del->br_startoff - got->br_startoff;
+               got_indlen = xfs_bmap_worst_indlen(ip, got->br_blockcount);
+
+               new.br_blockcount = got_endoff - del_endoff;
+               new_indlen = xfs_bmap_worst_indlen(ip, new.br_blockcount);
+
+               WARN_ON_ONCE(!got_indlen || !new_indlen);
+               stolen = xfs_bmap_split_indlen(da_old, &got_indlen, &new_indlen,
+                                                      del->br_blockcount);
+
+               got->br_startblock = nullstartblock((int)got_indlen);
+               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
+               trace_xfs_bmap_post_update(ip, *idx, 0, _THIS_IP_);
+
+               new.br_startoff = del_endoff;
+               new.br_state = got->br_state;
+               new.br_startblock = nullstartblock((int)new_indlen);
+
+               ++*idx;
+               xfs_iext_insert(ip, *idx, 1, &new, state);
+
+               da_new = got_indlen + new_indlen - stolen;
+               del->br_blockcount -= stolen;
+               break;
+       }
+
+       ASSERT(da_old >= da_new);
+       da_diff = da_old - da_new;
+       if (!isrt)
+               da_diff += del->br_blockcount;
+       if (da_diff)
+               xfs_mod_fdblocks(mp, da_diff, false);
+       return error;
+}
+
+void
+xfs_bmap_del_extent_cow(
+       struct xfs_inode        *ip,
+       xfs_extnum_t            *idx,
+       struct xfs_bmbt_irec    *got,
+       struct xfs_bmbt_irec    *del)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
+       struct xfs_bmbt_irec    new;
+       xfs_fileoff_t           del_endoff, got_endoff;
+       int                     state = BMAP_COWFORK;
+
+       XFS_STATS_INC(mp, xs_del_exlist);
+
+       del_endoff = del->br_startoff + del->br_blockcount;
+       got_endoff = got->br_startoff + got->br_blockcount;
+
+       ASSERT(*idx >= 0);
+       ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
+       ASSERT(del->br_blockcount > 0);
+       ASSERT(got->br_startoff <= del->br_startoff);
+       ASSERT(got_endoff >= del_endoff);
+       ASSERT(!isnullstartblock(got->br_startblock));
+
+       if (got->br_startoff == del->br_startoff)
+               state |= BMAP_LEFT_CONTIG;
+       if (got_endoff == del_endoff)
+               state |= BMAP_RIGHT_CONTIG;
+
+       switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) {
+       case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
+               /*
+                * Matches the whole extent.  Delete the entry.
+                */
+               xfs_iext_remove(ip, *idx, 1, state);
+               --*idx;
+               break;
+       case BMAP_LEFT_CONTIG:
+               /*
+                * Deleting the first part of the extent.
+                */
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               got->br_startoff = del_endoff;
+               got->br_blockcount -= del->br_blockcount;
+               got->br_startblock = del->br_startblock + del->br_blockcount;
+               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               break;
+       case BMAP_RIGHT_CONTIG:
+               /*
+                * Deleting the last part of the extent.
+                */
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               got->br_blockcount -= del->br_blockcount;
+               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+               break;
+       case 0:
+               /*
+                * Deleting the middle of the extent.
+                */
+               trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
+               got->br_blockcount = del->br_startoff - got->br_startoff;
+               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
+               trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
+
+               new.br_startoff = del_endoff;
+               new.br_blockcount = got_endoff - del_endoff;
+               new.br_state = got->br_state;
+               new.br_startblock = del->br_startblock + del->br_blockcount;
+
+               ++*idx;
+               xfs_iext_insert(ip, *idx, 1, &new, state);
+               break;
+       }
+}
+
 /*
  * Called by xfs_bmapi to update file extent records and the btree
  * after removing space (or undoing a delayed allocation).
@@ -5171,175 +5414,6 @@ done:
        return error;
 }
 
-/* Remove an extent from the CoW fork.  Similar to xfs_bmap_del_extent. */
-int
-xfs_bunmapi_cow(
-       struct xfs_inode                *ip,
-       struct xfs_bmbt_irec            *del)
-{
-       xfs_filblks_t                   da_new;
-       xfs_filblks_t                   da_old;
-       xfs_fsblock_t                   del_endblock = 0;
-       xfs_fileoff_t                   del_endoff;
-       int                             delay;
-       struct xfs_bmbt_rec_host        *ep;
-       int                             error;
-       struct xfs_bmbt_irec            got;
-       xfs_fileoff_t                   got_endoff;
-       struct xfs_ifork                *ifp;
-       struct xfs_mount                *mp;
-       xfs_filblks_t                   nblks;
-       struct xfs_bmbt_irec            new;
-       /* REFERENCED */
-       uint                            qfield;
-       xfs_filblks_t                   temp;
-       xfs_filblks_t                   temp2;
-       int                             state = BMAP_COWFORK;
-       int                             eof;
-       xfs_extnum_t                    eidx;
-
-       mp = ip->i_mount;
-       XFS_STATS_INC(mp, xs_del_exlist);
-
-       ep = xfs_bmap_search_extents(ip, del->br_startoff, XFS_COW_FORK, &eof,
-                       &eidx, &got, &new);
-
-       ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); ifp = ifp;
-       ASSERT((eidx >= 0) && (eidx < ifp->if_bytes /
-               (uint)sizeof(xfs_bmbt_rec_t)));
-       ASSERT(del->br_blockcount > 0);
-       ASSERT(got.br_startoff <= del->br_startoff);
-       del_endoff = del->br_startoff + del->br_blockcount;
-       got_endoff = got.br_startoff + got.br_blockcount;
-       ASSERT(got_endoff >= del_endoff);
-       delay = isnullstartblock(got.br_startblock);
-       ASSERT(isnullstartblock(del->br_startblock) == delay);
-       qfield = 0;
-       error = 0;
-       /*
-        * If deleting a real allocation, must free up the disk space.
-        */
-       if (!delay) {
-               nblks = del->br_blockcount;
-               qfield = XFS_TRANS_DQ_BCOUNT;
-               /*
-                * Set up del_endblock and cur for later.
-                */
-               del_endblock = del->br_startblock + del->br_blockcount;
-               da_old = da_new = 0;
-       } else {
-               da_old = startblockval(got.br_startblock);
-               da_new = 0;
-               nblks = 0;
-       }
-       qfield = qfield;
-       nblks = nblks;
-
-       /*
-        * Set flag value to use in switch statement.
-        * Left-contig is 2, right-contig is 1.
-        */
-       switch (((got.br_startoff == del->br_startoff) << 1) |
-               (got_endoff == del_endoff)) {
-       case 3:
-               /*
-                * Matches the whole extent.  Delete the entry.
-                */
-               xfs_iext_remove(ip, eidx, 1, BMAP_COWFORK);
-               --eidx;
-               break;
-
-       case 2:
-               /*
-                * Deleting the first part of the extent.
-                */
-               trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_);
-               xfs_bmbt_set_startoff(ep, del_endoff);
-               temp = got.br_blockcount - del->br_blockcount;
-               xfs_bmbt_set_blockcount(ep, temp);
-               if (delay) {
-                       temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
-                               da_old);
-                       xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-                       trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
-                       da_new = temp;
-                       break;
-               }
-               xfs_bmbt_set_startblock(ep, del_endblock);
-               trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
-               break;
-
-       case 1:
-               /*
-                * Deleting the last part of the extent.
-                */
-               temp = got.br_blockcount - del->br_blockcount;
-               trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(ep, temp);
-               if (delay) {
-                       temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
-                               da_old);
-                       xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-                       trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
-                       da_new = temp;
-                       break;
-               }
-               trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
-               break;
-
-       case 0:
-               /*
-                * Deleting the middle of the extent.
-                */
-               temp = del->br_startoff - got.br_startoff;
-               trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_);
-               xfs_bmbt_set_blockcount(ep, temp);
-               new.br_startoff = del_endoff;
-               temp2 = got_endoff - del_endoff;
-               new.br_blockcount = temp2;
-               new.br_state = got.br_state;
-               if (!delay) {
-                       new.br_startblock = del_endblock;
-               } else {
-                       temp = xfs_bmap_worst_indlen(ip, temp);
-                       xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
-                       temp2 = xfs_bmap_worst_indlen(ip, temp2);
-                       new.br_startblock = nullstartblock((int)temp2);
-                       da_new = temp + temp2;
-                       while (da_new > da_old) {
-                               if (temp) {
-                                       temp--;
-                                       da_new--;
-                                       xfs_bmbt_set_startblock(ep,
-                                               nullstartblock((int)temp));
-                               }
-                               if (da_new == da_old)
-                                       break;
-                               if (temp2) {
-                                       temp2--;
-                                       da_new--;
-                                       new.br_startblock =
-                                               nullstartblock((int)temp2);
-                               }
-                       }
-               }
-               trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
-               xfs_iext_insert(ip, eidx + 1, 1, &new, state);
-               ++eidx;
-               break;
-       }
-
-       /*
-        * Account for change in delayed indirect blocks.
-        * Nothing to do for disk quota accounting here.
-        */
-       ASSERT(da_old >= da_new);
-       if (da_old > da_new)
-               xfs_mod_fdblocks(mp, (int64_t)(da_old - da_new), false);
-
-       return error;
-}
-
 /*
  * Unmap (remove) blocks from a file.
  * If nexts is nonzero then the number of extents to remove is limited to
index f97db7132564569dc7f2aefbf05f27da719c8e10..7cae6ec27fa6b26a84984fddb3dc35d6556e2122 100644 (file)
@@ -190,6 +190,8 @@ void        xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
 #define        XFS_BMAP_TRACE_EXLIST(ip,c,w)
 #endif
 
+void   xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno,
+               xfs_filblks_t len);
 int    xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
 void   xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
 void   xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
@@ -221,7 +223,11 @@ int        xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip,
                xfs_fileoff_t bno, xfs_filblks_t len, int flags,
                xfs_extnum_t nexts, xfs_fsblock_t *firstblock,
                struct xfs_defer_ops *dfops, int *done);
-int    xfs_bunmapi_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *del);
+int    xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork,
+               xfs_extnum_t *idx, struct xfs_bmbt_irec *got,
+               struct xfs_bmbt_irec *del);
+void   xfs_bmap_del_extent_cow(struct xfs_inode *ip, xfs_extnum_t *idx,
+               struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del);
 int    xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx,
                xfs_extnum_t num);
 uint   xfs_default_attroffset(struct xfs_inode *ip);
index 5c8e6f2ce44f461d343a98b6b49ad6b0b09a3b8b..0e80993c8a5914d3dfa1f861b2b459d7a513d67a 100644 (file)
@@ -4826,7 +4826,7 @@ xfs_btree_calc_size(
        return rval;
 }
 
-int
+static int
 xfs_btree_count_blocks_helper(
        struct xfs_btree_cur    *cur,
        int                     level,
index 613c5cf1943646764880ba3beeffb98667dc5268..5c2929f94bd3bf27411f860b57697b9d899312d1 100644 (file)
@@ -199,9 +199,9 @@ xfs_defer_intake_work(
        struct xfs_defer_pending        *dfp;
 
        list_for_each_entry(dfp, &dop->dop_intake, dfp_list) {
-               trace_xfs_defer_intake_work(tp->t_mountp, dfp);
                dfp->dfp_intent = dfp->dfp_type->create_intent(tp,
                                dfp->dfp_count);
+               trace_xfs_defer_intake_work(tp->t_mountp, dfp);
                list_sort(tp->t_mountp, &dfp->dfp_work,
                                dfp->dfp_type->diff_items);
                list_for_each(li, &dfp->dfp_work)
@@ -221,21 +221,14 @@ xfs_defer_trans_abort(
        struct xfs_defer_pending        *dfp;
 
        trace_xfs_defer_trans_abort(tp->t_mountp, dop);
-       /*
-        * If the transaction was committed, drop the intent reference
-        * since we're bailing out of here. The other reference is
-        * dropped when the intent hits the AIL.  If the transaction
-        * was not committed, the intent is freed by the intent item
-        * unlock handler on abort.
-        */
-       if (!dop->dop_committed)
-               return;
 
-       /* Abort intent items. */
+       /* Abort intent items that don't have a done item. */
        list_for_each_entry(dfp, &dop->dop_pending, dfp_list) {
                trace_xfs_defer_pending_abort(tp->t_mountp, dfp);
-               if (!dfp->dfp_done)
+               if (dfp->dfp_intent && !dfp->dfp_done) {
                        dfp->dfp_type->abort_intent(dfp->dfp_intent);
+                       dfp->dfp_intent = NULL;
+               }
        }
 
        /* Shut down FS. */
index 3cc3cf7674746f279fcb0acf4eae27d49d089814..ac9a003dd29acf80d7c766788cb40d1f98d9132c 100644 (file)
@@ -191,8 +191,7 @@ xfs_dquot_buf_verify_crc(
        if (mp->m_quotainfo)
                ndquots = mp->m_quotainfo->qi_dqperchunk;
        else
-               ndquots = xfs_calc_dquots_per_chunk(
-                                       XFS_BB_TO_FSB(mp, bp->b_length));
+               ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
 
        for (i = 0; i < ndquots; i++, d++) {
                if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
index f6547fc5e016e75a130a738c3e4a1b3a087d7281..6b7579e7b60a228ee6e633221bc64952f4a93a41 100644 (file)
@@ -865,7 +865,6 @@ typedef struct xfs_timestamp {
  * padding field for v3 inodes.
  */
 #define        XFS_DINODE_MAGIC                0x494e  /* 'IN' */
-#define XFS_DINODE_GOOD_VERSION(v)     ((v) >= 1 && (v) <= 3)
 typedef struct xfs_dinode {
        __be16          di_magic;       /* inode magic # = XFS_DINODE_MAGIC */
        __be16          di_mode;        /* mode and type of file */
index 8de9a3a29589bd59c0684c8eab278db3edceba53..134424fac434fdd7fdd3cecf12d3007712b9734b 100644 (file)
@@ -57,6 +57,17 @@ xfs_inobp_check(
 }
 #endif
 
+bool
+xfs_dinode_good_version(
+       struct xfs_mount *mp,
+       __u8            version)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               return version == 3;
+
+       return version == 1 || version == 2;
+}
+
 /*
  * If we are doing readahead on an inode buffer, we might be in log recovery
  * reading an inode allocation buffer that hasn't yet been replayed, and hence
@@ -91,7 +102,7 @@ xfs_inode_buf_verify(
 
                dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog));
                di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
-                           XFS_DINODE_GOOD_VERSION(dip->di_version);
+                       xfs_dinode_good_version(mp, dip->di_version);
                if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
                                                XFS_ERRTAG_ITOBP_INOTOBP,
                                                XFS_RANDOM_ITOBP_INOTOBP))) {
index 62d9d4681c8c28a1294b575903f0720693bc6666..3cfe12a4f58ac8560e1cd92e529a85477ff5ee02 100644 (file)
@@ -74,6 +74,8 @@ void  xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from);
 void   xfs_log_dinode_to_disk(struct xfs_log_dinode *from,
                               struct xfs_dinode *to);
 
+bool   xfs_dinode_good_version(struct xfs_mount *mp, __u8 version);
+
 #if defined(DEBUG)
 void   xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
 #else
index a314fc7b56fa5b0fcfb0e234a9a931eda6de7e73..6e4f7f900fea4c30f44477dc258db5334b980486 100644 (file)
@@ -249,6 +249,7 @@ xfs_file_dio_aio_read(
        struct xfs_inode        *ip = XFS_I(inode);
        loff_t                  isize = i_size_read(inode);
        size_t                  count = iov_iter_count(to);
+       loff_t                  end = iocb->ki_pos + count - 1;
        struct iov_iter         data;
        struct xfs_buftarg      *target;
        ssize_t                 ret = 0;
@@ -272,49 +273,21 @@ xfs_file_dio_aio_read(
 
        file_accessed(iocb->ki_filp);
 
-       /*
-        * Locking is a bit tricky here. If we take an exclusive lock for direct
-        * IO, we effectively serialise all new concurrent read IO to this file
-        * and block it behind IO that is currently in progress because IO in
-        * progress holds the IO lock shared. We only need to hold the lock
-        * exclusive to blow away the page cache, so only take lock exclusively
-        * if the page cache needs invalidation. This allows the normal direct
-        * IO case of no page cache pages to proceeed concurrently without
-        * serialisation.
-        */
        xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
        if (mapping->nrpages) {
-               xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
-               xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);
+               ret = filemap_write_and_wait_range(mapping, iocb->ki_pos, end);
+               if (ret)
+                       goto out_unlock;
 
                /*
-                * The generic dio code only flushes the range of the particular
-                * I/O. Because we take an exclusive lock here, this whole
-                * sequence is considerably more expensive for us. This has a
-                * noticeable performance impact for any file with cached pages,
-                * even when outside of the range of the particular I/O.
-                *
-                * Hence, amortize the cost of the lock against a full file
-                * flush and reduce the chances of repeated iolock cycles going
-                * forward.
+                * Invalidate whole pages. This can return an error if we fail
+                * to invalidate a page, but this should never happen on XFS.
+                * Warn if it does fail.
                 */
-               if (mapping->nrpages) {
-                       ret = filemap_write_and_wait(mapping);
-                       if (ret) {
-                               xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL);
-                               return ret;
-                       }
-
-                       /*
-                        * Invalidate whole pages. This can return an error if
-                        * we fail to invalidate a page, but this should never
-                        * happen on XFS. Warn if it does fail.
-                        */
-                       ret = invalidate_inode_pages2(mapping);
-                       WARN_ON_ONCE(ret);
-                       ret = 0;
-               }
-               xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
+               ret = invalidate_inode_pages2_range(mapping,
+                               iocb->ki_pos >> PAGE_SHIFT, end >> PAGE_SHIFT);
+               WARN_ON_ONCE(ret);
+               ret = 0;
        }
 
        data = *to;
@@ -324,8 +297,9 @@ xfs_file_dio_aio_read(
                iocb->ki_pos += ret;
                iov_iter_advance(to, ret);
        }
-       xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
 
+out_unlock:
+       xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
        return ret;
 }
 
@@ -570,61 +544,49 @@ xfs_file_dio_aio_write(
        if ((iocb->ki_pos | count) & target->bt_logical_sectormask)
                return -EINVAL;
 
-       /* "unaligned" here means not aligned to a filesystem block */
-       if ((iocb->ki_pos & mp->m_blockmask) ||
-           ((iocb->ki_pos + count) & mp->m_blockmask))
-               unaligned_io = 1;
-
        /*
-        * We don't need to take an exclusive lock unless there page cache needs
-        * to be invalidated or unaligned IO is being executed. We don't need to
-        * consider the EOF extension case here because
-        * xfs_file_aio_write_checks() will relock the inode as necessary for
-        * EOF zeroing cases and fill out the new inode size as appropriate.
+        * Don't take the exclusive iolock here unless the I/O is unaligned to
+        * the file system block size.  We don't need to consider the EOF
+        * extension case here because xfs_file_aio_write_checks() will relock
+        * the inode as necessary for EOF zeroing cases and fill out the new
+        * inode size as appropriate.
         */
-       if (unaligned_io || mapping->nrpages)
+       if ((iocb->ki_pos & mp->m_blockmask) ||
+           ((iocb->ki_pos + count) & mp->m_blockmask)) {
+               unaligned_io = 1;
                iolock = XFS_IOLOCK_EXCL;
-       else
+       } else {
                iolock = XFS_IOLOCK_SHARED;
-       xfs_rw_ilock(ip, iolock);
-
-       /*
-        * Recheck if there are cached pages that need invalidate after we got
-        * the iolock to protect against other threads adding new pages while
-        * we were waiting for the iolock.
-        */
-       if (mapping->nrpages && iolock == XFS_IOLOCK_SHARED) {
-               xfs_rw_iunlock(ip, iolock);
-               iolock = XFS_IOLOCK_EXCL;
-               xfs_rw_ilock(ip, iolock);
        }
 
+       xfs_rw_ilock(ip, iolock);
+
        ret = xfs_file_aio_write_checks(iocb, from, &iolock);
        if (ret)
                goto out;
        count = iov_iter_count(from);
        end = iocb->ki_pos + count - 1;
 
-       /*
-        * See xfs_file_dio_aio_read() for why we do a full-file flush here.
-        */
        if (mapping->nrpages) {
-               ret = filemap_write_and_wait(VFS_I(ip)->i_mapping);
+               ret = filemap_write_and_wait_range(mapping, iocb->ki_pos, end);
                if (ret)
                        goto out;
+
                /*
                 * Invalidate whole pages. This can return an error if we fail
                 * to invalidate a page, but this should never happen on XFS.
                 * Warn if it does fail.
                 */
-               ret = invalidate_inode_pages2(VFS_I(ip)->i_mapping);
+               ret = invalidate_inode_pages2_range(mapping,
+                               iocb->ki_pos >> PAGE_SHIFT, end >> PAGE_SHIFT);
                WARN_ON_ONCE(ret);
                ret = 0;
        }
 
        /*
         * If we are doing unaligned IO, wait for all other IO to drain,
-        * otherwise demote the lock if we had to flush cached pages
+        * otherwise demote the lock if we had to take the exclusive lock
+        * for other reasons in xfs_file_aio_write_checks.
         */
        if (unaligned_io)
                inode_dio_wait(inode);
@@ -947,134 +909,6 @@ out_unlock:
        return error;
 }
 
-/*
- * Flush all file writes out to disk.
- */
-static int
-xfs_file_wait_for_io(
-       struct inode    *inode,
-       loff_t          offset,
-       size_t          len)
-{
-       loff_t          rounding;
-       loff_t          ioffset;
-       loff_t          iendoffset;
-       loff_t          bs;
-       int             ret;
-
-       bs = inode->i_sb->s_blocksize;
-       inode_dio_wait(inode);
-
-       rounding = max_t(xfs_off_t, bs, PAGE_SIZE);
-       ioffset = round_down(offset, rounding);
-       iendoffset = round_up(offset + len, rounding) - 1;
-       ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
-                                          iendoffset);
-       return ret;
-}
-
-/* Hook up to the VFS reflink function */
-STATIC int
-xfs_file_share_range(
-       struct file     *file_in,
-       loff_t          pos_in,
-       struct file     *file_out,
-       loff_t          pos_out,
-       u64             len,
-       bool            is_dedupe)
-{
-       struct inode    *inode_in;
-       struct inode    *inode_out;
-       ssize_t         ret;
-       loff_t          bs;
-       loff_t          isize;
-       int             same_inode;
-       loff_t          blen;
-       unsigned int    flags = 0;
-
-       inode_in = file_inode(file_in);
-       inode_out = file_inode(file_out);
-       bs = inode_out->i_sb->s_blocksize;
-
-       /* Don't touch certain kinds of inodes */
-       if (IS_IMMUTABLE(inode_out))
-               return -EPERM;
-       if (IS_SWAPFILE(inode_in) ||
-           IS_SWAPFILE(inode_out))
-               return -ETXTBSY;
-
-       /* Reflink only works within this filesystem. */
-       if (inode_in->i_sb != inode_out->i_sb)
-               return -EXDEV;
-       same_inode = (inode_in->i_ino == inode_out->i_ino);
-
-       /* Don't reflink dirs, pipes, sockets... */
-       if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
-               return -EISDIR;
-       if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode))
-               return -EINVAL;
-       if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
-               return -EINVAL;
-
-       /* Don't share DAX file data for now. */
-       if (IS_DAX(inode_in) || IS_DAX(inode_out))
-               return -EINVAL;
-
-       /* Are we going all the way to the end? */
-       isize = i_size_read(inode_in);
-       if (isize == 0)
-               return 0;
-       if (len == 0)
-               len = isize - pos_in;
-
-       /* Ensure offsets don't wrap and the input is inside i_size */
-       if (pos_in + len < pos_in || pos_out + len < pos_out ||
-           pos_in + len > isize)
-               return -EINVAL;
-
-       /* Don't allow dedupe past EOF in the dest file */
-       if (is_dedupe) {
-               loff_t  disize;
-
-               disize = i_size_read(inode_out);
-               if (pos_out >= disize || pos_out + len > disize)
-                       return -EINVAL;
-       }
-
-       /* If we're linking to EOF, continue to the block boundary. */
-       if (pos_in + len == isize)
-               blen = ALIGN(isize, bs) - pos_in;
-       else
-               blen = len;
-
-       /* Only reflink if we're aligned to block boundaries */
-       if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) ||
-           !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs))
-               return -EINVAL;
-
-       /* Don't allow overlapped reflink within the same file */
-       if (same_inode && pos_out + blen > pos_in && pos_out < pos_in + blen)
-               return -EINVAL;
-
-       /* Wait for the completion of any pending IOs on srcfile */
-       ret = xfs_file_wait_for_io(inode_in, pos_in, len);
-       if (ret)
-               goto out;
-       ret = xfs_file_wait_for_io(inode_out, pos_out, len);
-       if (ret)
-               goto out;
-
-       if (is_dedupe)
-               flags |= XFS_REFLINK_DEDUPE;
-       ret = xfs_reflink_remap_range(XFS_I(inode_in), pos_in, XFS_I(inode_out),
-                       pos_out, len, flags);
-       if (ret < 0)
-               goto out;
-
-out:
-       return ret;
-}
-
 STATIC ssize_t
 xfs_file_copy_range(
        struct file     *file_in,
@@ -1086,7 +920,7 @@ xfs_file_copy_range(
 {
        int             error;
 
-       error = xfs_file_share_range(file_in, pos_in, file_out, pos_out,
+       error = xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
                                     len, false);
        if (error)
                return error;
@@ -1101,7 +935,7 @@ xfs_file_clone_range(
        loff_t          pos_out,
        u64             len)
 {
-       return xfs_file_share_range(file_in, pos_in, file_out, pos_out,
+       return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out,
                                     len, false);
 }
 
@@ -1124,7 +958,7 @@ xfs_file_dedupe_range(
        if (len > XFS_MAX_DEDUPE_LEN)
                len = XFS_MAX_DEDUPE_LEN;
 
-       error = xfs_file_share_range(src_file, loff, dst_file, dst_loff,
+       error = xfs_reflink_remap_range(src_file, loff, dst_file, dst_loff,
                                     len, true);
        if (error)
                return error;
index 14796b744e0a1ebb9f8d428131d2522316262e82..f295049db68159523ac936727c748e7264f80993 100644 (file)
@@ -1656,9 +1656,9 @@ void
 xfs_inode_set_cowblocks_tag(
        xfs_inode_t     *ip)
 {
-       trace_xfs_inode_set_eofblocks_tag(ip);
+       trace_xfs_inode_set_cowblocks_tag(ip);
        return __xfs_inode_set_eofblocks_tag(ip, xfs_queue_cowblocks,
-                       trace_xfs_perag_set_eofblocks,
+                       trace_xfs_perag_set_cowblocks,
                        XFS_ICI_COWBLOCKS_TAG);
 }
 
@@ -1666,7 +1666,7 @@ void
 xfs_inode_clear_cowblocks_tag(
        xfs_inode_t     *ip)
 {
-       trace_xfs_inode_clear_eofblocks_tag(ip);
+       trace_xfs_inode_clear_cowblocks_tag(ip);
        return __xfs_inode_clear_eofblocks_tag(ip,
-                       trace_xfs_perag_clear_eofblocks, XFS_ICI_COWBLOCKS_TAG);
+                       trace_xfs_perag_clear_cowblocks, XFS_ICI_COWBLOCKS_TAG);
 }
index d907eb9f8ef32a079f845c4aa4731bb3413fcb25..436e109bb01e59d32bda87e9dd43ab3229cba509 100644 (file)
@@ -566,6 +566,17 @@ xfs_file_iomap_begin_delay(
        xfs_bmap_search_extents(ip, offset_fsb, XFS_DATA_FORK, &eof, &idx,
                        &got, &prev);
        if (!eof && got.br_startoff <= offset_fsb) {
+               if (xfs_is_reflink_inode(ip)) {
+                       bool            shared;
+
+                       end_fsb = min(XFS_B_TO_FSB(mp, offset + count),
+                                       maxbytes_fsb);
+                       xfs_trim_extent(&got, offset_fsb, end_fsb - offset_fsb);
+                       error = xfs_reflink_reserve_cow(ip, &got, &shared);
+                       if (error)
+                               goto out_unlock;
+               }
+
                trace_xfs_iomap_found(ip, offset, count, 0, &got);
                goto done;
        }
@@ -961,19 +972,13 @@ xfs_file_iomap_begin(
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_bmbt_irec    imap;
        xfs_fileoff_t           offset_fsb, end_fsb;
-       bool                    shared, trimmed;
        int                     nimaps = 1, error = 0;
+       bool                    shared = false, trimmed = false;
        unsigned                lockmode;
 
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) {
-               error = xfs_reflink_reserve_cow_range(ip, offset, length);
-               if (error < 0)
-                       return error;
-       }
-
        if ((flags & IOMAP_WRITE) && !IS_DAX(inode) &&
                   !xfs_get_extsz_hint(ip)) {
                /* Reserve delalloc blocks for regular writeback. */
@@ -981,7 +986,16 @@ xfs_file_iomap_begin(
                                iomap);
        }
 
-       lockmode = xfs_ilock_data_map_shared(ip);
+       /*
+        * COW writes will allocate delalloc space, so we need to make sure
+        * to take the lock exclusively here.
+        */
+       if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) {
+               lockmode = XFS_ILOCK_EXCL;
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+       } else {
+               lockmode = xfs_ilock_data_map_shared(ip);
+       }
 
        ASSERT(offset <= mp->m_super->s_maxbytes);
        if ((xfs_fsize_t)offset + length > mp->m_super->s_maxbytes)
@@ -991,16 +1005,24 @@ xfs_file_iomap_begin(
 
        error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap,
                               &nimaps, 0);
-       if (error) {
-               xfs_iunlock(ip, lockmode);
-               return error;
+       if (error)
+               goto out_unlock;
+
+       if (flags & IOMAP_REPORT) {
+               /* Trim the mapping to the nearest shared extent boundary. */
+               error = xfs_reflink_trim_around_shared(ip, &imap, &shared,
+                               &trimmed);
+               if (error)
+                       goto out_unlock;
        }
 
-       /* Trim the mapping to the nearest shared extent boundary. */
-       error = xfs_reflink_trim_around_shared(ip, &imap, &shared, &trimmed);
-       if (error) {
-               xfs_iunlock(ip, lockmode);
-               return error;
+       if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) {
+               error = xfs_reflink_reserve_cow(ip, &imap, &shared);
+               if (error)
+                       goto out_unlock;
+
+               end_fsb = imap.br_startoff + imap.br_blockcount;
+               length = XFS_FSB_TO_B(mp, end_fsb) - offset;
        }
 
        if ((flags & IOMAP_WRITE) && imap_needs_alloc(inode, &imap, nimaps)) {
@@ -1039,6 +1061,9 @@ xfs_file_iomap_begin(
        if (shared)
                iomap->flags |= IOMAP_F_SHARED;
        return 0;
+out_unlock:
+       xfs_iunlock(ip, lockmode);
+       return error;
 }
 
 static int
index fc7873942bea51866611aee5a7437f3d4a036a67..b341f10cf4810bf3716aec354f33fbdbf9ab5494 100644 (file)
@@ -1009,6 +1009,7 @@ xfs_mountfs(
  out_quota:
        xfs_qm_unmount_quotas(mp);
  out_rtunmount:
+       mp->m_super->s_flags &= ~MS_ACTIVE;
        xfs_rtunmount_inodes(mp);
  out_rele_rip:
        IRELE(rip);
index 5965e9455d91e03621680a08493610085d5a926c..a279b4e7f5feaa83a0cf1fbbfaf1c4d8e393ecbc 100644 (file)
@@ -182,7 +182,8 @@ xfs_reflink_trim_around_shared(
        if (!xfs_is_reflink_inode(ip) ||
            ISUNWRITTEN(irec) ||
            irec->br_startblock == HOLESTARTBLOCK ||
-           irec->br_startblock == DELAYSTARTBLOCK) {
+           irec->br_startblock == DELAYSTARTBLOCK ||
+           isnullstartblock(irec->br_startblock)) {
                *shared = false;
                return 0;
        }
@@ -227,50 +228,54 @@ xfs_reflink_trim_around_shared(
        }
 }
 
-/* Create a CoW reservation for a range of blocks within a file. */
-static int
-__xfs_reflink_reserve_cow(
+/*
+ * Trim the passed in imap to the next shared/unshared extent boundary, and
+ * if imap->br_startoff points to a shared extent reserve space for it in the
+ * COW fork.  In this case *shared is set to true, else to false.
+ *
+ * Note that imap will always contain the block numbers for the existing blocks
+ * in the data fork, as the upper layers need them for read-modify-write
+ * operations.
+ */
+int
+xfs_reflink_reserve_cow(
        struct xfs_inode        *ip,
-       xfs_fileoff_t           *offset_fsb,
-       xfs_fileoff_t           end_fsb,
-       bool                    *skipped)
+       struct xfs_bmbt_irec    *imap,
+       bool                    *shared)
 {
-       struct xfs_bmbt_irec    got, prev, imap;
-       xfs_fileoff_t           orig_end_fsb;
-       int                     nimaps, eof = 0, error = 0;
-       bool                    shared = false, trimmed = false;
+       struct xfs_bmbt_irec    got, prev;
+       xfs_fileoff_t           end_fsb, orig_end_fsb;
+       int                     eof = 0, error = 0;
+       bool                    trimmed;
        xfs_extnum_t            idx;
        xfs_extlen_t            align;
 
-       /* Already reserved?  Skip the refcount btree access. */
-       xfs_bmap_search_extents(ip, *offset_fsb, XFS_COW_FORK, &eof, &idx,
+       /*
+        * Search the COW fork extent list first.  This serves two purposes:
+        * first this implement the speculative preallocation using cowextisze,
+        * so that we also unshared block adjacent to shared blocks instead
+        * of just the shared blocks themselves.  Second the lookup in the
+        * extent list is generally faster than going out to the shared extent
+        * tree.
+        */
+       xfs_bmap_search_extents(ip, imap->br_startoff, XFS_COW_FORK, &eof, &idx,
                        &got, &prev);
-       if (!eof && got.br_startoff <= *offset_fsb) {
-               end_fsb = orig_end_fsb = got.br_startoff + got.br_blockcount;
-               trace_xfs_reflink_cow_found(ip, &got);
-               goto done;
-       }
+       if (!eof && got.br_startoff <= imap->br_startoff) {
+               trace_xfs_reflink_cow_found(ip, imap);
+               xfs_trim_extent(imap, got.br_startoff, got.br_blockcount);
 
-       /* Read extent from the source file. */
-       nimaps = 1;
-       error = xfs_bmapi_read(ip, *offset_fsb, end_fsb - *offset_fsb,
-                       &imap, &nimaps, 0);
-       if (error)
-               goto out_unlock;
-       ASSERT(nimaps == 1);
+               *shared = true;
+               return 0;
+       }
 
        /* Trim the mapping to the nearest shared extent boundary. */
-       error = xfs_reflink_trim_around_shared(ip, &imap, &shared, &trimmed);
+       error = xfs_reflink_trim_around_shared(ip, imap, shared, &trimmed);
        if (error)
-               goto out_unlock;
-
-       end_fsb = orig_end_fsb = imap.br_startoff + imap.br_blockcount;
+               return error;
 
        /* Not shared?  Just report the (potentially capped) extent. */
-       if (!shared) {
-               *skipped = true;
-               goto done;
-       }
+       if (!*shared)
+               return 0;
 
        /*
         * Fork all the shared blocks from our write offset until the end of
@@ -278,72 +283,38 @@ __xfs_reflink_reserve_cow(
         */
        error = xfs_qm_dqattach_locked(ip, 0);
        if (error)
-               goto out_unlock;
+               return error;
+
+       end_fsb = orig_end_fsb = imap->br_startoff + imap->br_blockcount;
 
        align = xfs_eof_alignment(ip, xfs_get_cowextsz_hint(ip));
        if (align)
                end_fsb = roundup_64(end_fsb, align);
 
 retry:
-       error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, *offset_fsb,
-                       end_fsb - *offset_fsb, &got,
-                       &prev, &idx, eof);
+       error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff,
+                       end_fsb - imap->br_startoff, &got, &prev, &idx, eof);
        switch (error) {
        case 0:
                break;
        case -ENOSPC:
        case -EDQUOT:
                /* retry without any preallocation */
-               trace_xfs_reflink_cow_enospc(ip, &imap);
+               trace_xfs_reflink_cow_enospc(ip, imap);
                if (end_fsb != orig_end_fsb) {
                        end_fsb = orig_end_fsb;
                        goto retry;
                }
                /*FALLTHRU*/
        default:
-               goto out_unlock;
+               return error;
        }
 
        if (end_fsb != orig_end_fsb)
                xfs_inode_set_cowblocks_tag(ip);
 
        trace_xfs_reflink_cow_alloc(ip, &got);
-done:
-       *offset_fsb = end_fsb;
-out_unlock:
-       return error;
-}
-
-/* Create a CoW reservation for part of a file. */
-int
-xfs_reflink_reserve_cow_range(
-       struct xfs_inode        *ip,
-       xfs_off_t               offset,
-       xfs_off_t               count)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_fileoff_t           offset_fsb, end_fsb;
-       bool                    skipped = false;
-       int                     error;
-
-       trace_xfs_reflink_reserve_cow_range(ip, offset, count);
-
-       offset_fsb = XFS_B_TO_FSBT(mp, offset);
-       end_fsb = XFS_B_TO_FSB(mp, offset + count);
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       while (offset_fsb < end_fsb) {
-               error = __xfs_reflink_reserve_cow(ip, &offset_fsb, end_fsb,
-                               &skipped);
-               if (error) {
-                       trace_xfs_reflink_reserve_cow_range_error(ip, error,
-                               _RET_IP_);
-                       break;
-               }
-       }
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-       return error;
+       return 0;
 }
 
 /* Allocate all CoW reservations covering a range of blocks in a file. */
@@ -358,9 +329,8 @@ __xfs_reflink_allocate_cow(
        struct xfs_defer_ops    dfops;
        struct xfs_trans        *tp;
        xfs_fsblock_t           first_block;
-       xfs_fileoff_t           next_fsb;
        int                     nimaps = 1, error;
-       bool                    skipped = false;
+       bool                    shared;
 
        xfs_defer_init(&dfops, &first_block);
 
@@ -371,33 +341,38 @@ __xfs_reflink_allocate_cow(
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-       next_fsb = *offset_fsb;
-       error = __xfs_reflink_reserve_cow(ip, &next_fsb, end_fsb, &skipped);
+       /* Read extent from the source file. */
+       nimaps = 1;
+       error = xfs_bmapi_read(ip, *offset_fsb, end_fsb - *offset_fsb,
+                       &imap, &nimaps, 0);
+       if (error)
+               goto out_unlock;
+       ASSERT(nimaps == 1);
+
+       error = xfs_reflink_reserve_cow(ip, &imap, &shared);
        if (error)
                goto out_trans_cancel;
 
-       if (skipped) {
-               *offset_fsb = next_fsb;
+       if (!shared) {
+               *offset_fsb = imap.br_startoff + imap.br_blockcount;
                goto out_trans_cancel;
        }
 
        xfs_trans_ijoin(tp, ip, 0);
-       error = xfs_bmapi_write(tp, ip, *offset_fsb, next_fsb - *offset_fsb,
+       error = xfs_bmapi_write(tp, ip, imap.br_startoff, imap.br_blockcount,
                        XFS_BMAPI_COWFORK, &first_block,
                        XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK),
                        &imap, &nimaps, &dfops);
        if (error)
                goto out_trans_cancel;
 
-       /* We might not have been able to map the whole delalloc extent */
-       *offset_fsb = min(*offset_fsb + imap.br_blockcount, next_fsb);
-
        error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
                goto out_trans_cancel;
 
        error = xfs_trans_commit(tp);
 
+       *offset_fsb = imap.br_startoff + imap.br_blockcount;
 out_unlock:
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
@@ -536,58 +511,49 @@ xfs_reflink_cancel_cow_blocks(
        xfs_fileoff_t                   offset_fsb,
        xfs_fileoff_t                   end_fsb)
 {
-       struct xfs_bmbt_irec            irec;
-       xfs_filblks_t                   count_fsb;
+       struct xfs_ifork                *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
+       struct xfs_bmbt_irec            got, prev, del;
+       xfs_extnum_t                    idx;
        xfs_fsblock_t                   firstfsb;
        struct xfs_defer_ops            dfops;
-       int                             error = 0;
-       int                             nimaps;
+       int                             error = 0, eof = 0;
 
        if (!xfs_is_reflink_inode(ip))
                return 0;
 
-       /* Go find the old extent in the CoW fork. */
-       while (offset_fsb < end_fsb) {
-               nimaps = 1;
-               count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb);
-               error = xfs_bmapi_read(ip, offset_fsb, count_fsb, &irec,
-                               &nimaps, XFS_BMAPI_COWFORK);
-               if (error)
-                       break;
-               ASSERT(nimaps == 1);
-
-               trace_xfs_reflink_cancel_cow(ip, &irec);
+       xfs_bmap_search_extents(ip, offset_fsb, XFS_COW_FORK, &eof, &idx,
+                       &got, &prev);
+       if (eof)
+               return 0;
 
-               if (irec.br_startblock == DELAYSTARTBLOCK) {
-                       /* Free a delayed allocation. */
-                       xfs_mod_fdblocks(ip->i_mount, irec.br_blockcount,
-                                       false);
-                       ip->i_delayed_blks -= irec.br_blockcount;
+       while (got.br_startoff < end_fsb) {
+               del = got;
+               xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb);
+               trace_xfs_reflink_cancel_cow(ip, &del);
 
-                       /* Remove the mapping from the CoW fork. */
-                       error = xfs_bunmapi_cow(ip, &irec);
+               if (isnullstartblock(del.br_startblock)) {
+                       error = xfs_bmap_del_extent_delay(ip, XFS_COW_FORK,
+                                       &idx, &got, &del);
                        if (error)
                                break;
-               } else if (irec.br_startblock == HOLESTARTBLOCK) {
-                       /* empty */
                } else {
                        xfs_trans_ijoin(*tpp, ip, 0);
                        xfs_defer_init(&dfops, &firstfsb);
 
                        /* Free the CoW orphan record. */
                        error = xfs_refcount_free_cow_extent(ip->i_mount,
-                                       &dfops, irec.br_startblock,
-                                       irec.br_blockcount);
+                                       &dfops, del.br_startblock,
+                                       del.br_blockcount);
                        if (error)
                                break;
 
                        xfs_bmap_add_free(ip->i_mount, &dfops,
-                                       irec.br_startblock, irec.br_blockcount,
+                                       del.br_startblock, del.br_blockcount,
                                        NULL);
 
                        /* Update quota accounting */
                        xfs_trans_mod_dquot_byino(*tpp, ip, XFS_TRANS_DQ_BCOUNT,
-                                       -(long)irec.br_blockcount);
+                                       -(long)del.br_blockcount);
 
                        /* Roll the transaction */
                        error = xfs_defer_finish(tpp, &dfops, ip);
@@ -597,15 +563,18 @@ xfs_reflink_cancel_cow_blocks(
                        }
 
                        /* Remove the mapping from the CoW fork. */
-                       error = xfs_bunmapi_cow(ip, &irec);
-                       if (error)
-                               break;
+                       xfs_bmap_del_extent_cow(ip, &idx, &got, &del);
                }
 
-               /* Roll on... */
-               offset_fsb = irec.br_startoff + irec.br_blockcount;
+               if (++idx >= ifp->if_bytes / sizeof(struct xfs_bmbt_rec))
+                       break;
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got);
        }
 
+       /* clear tag if cow fork is emptied */
+       if (!ifp->if_bytes)
+               xfs_inode_clear_cowblocks_tag(ip);
+
        return error;
 }
 
@@ -668,25 +637,26 @@ xfs_reflink_end_cow(
        xfs_off_t                       offset,
        xfs_off_t                       count)
 {
-       struct xfs_bmbt_irec            irec;
-       struct xfs_bmbt_irec            uirec;
+       struct xfs_ifork                *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
+       struct xfs_bmbt_irec            got, prev, del;
        struct xfs_trans                *tp;
        xfs_fileoff_t                   offset_fsb;
        xfs_fileoff_t                   end_fsb;
-       xfs_filblks_t                   count_fsb;
        xfs_fsblock_t                   firstfsb;
        struct xfs_defer_ops            dfops;
-       int                             error;
+       int                             error, eof = 0;
        unsigned int                    resblks;
-       xfs_filblks_t                   ilen;
        xfs_filblks_t                   rlen;
-       int                             nimaps;
+       xfs_extnum_t                    idx;
 
        trace_xfs_reflink_end_cow(ip, offset, count);
 
+       /* No COW extents?  That's easy! */
+       if (ifp->if_bytes == 0)
+               return 0;
+
        offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset);
        end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count);
-       count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb);
 
        /* Start a rolling transaction to switch the mappings */
        resblks = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK);
@@ -698,72 +668,65 @@ xfs_reflink_end_cow(
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
-       /* Go find the old extent in the CoW fork. */
-       while (offset_fsb < end_fsb) {
-               /* Read extent from the source file */
-               nimaps = 1;
-               count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb);
-               error = xfs_bmapi_read(ip, offset_fsb, count_fsb, &irec,
-                               &nimaps, XFS_BMAPI_COWFORK);
-               if (error)
-                       goto out_cancel;
-               ASSERT(nimaps == 1);
+       xfs_bmap_search_extents(ip, end_fsb - 1, XFS_COW_FORK, &eof, &idx,
+                       &got, &prev);
 
-               ASSERT(irec.br_startblock != DELAYSTARTBLOCK);
-               trace_xfs_reflink_cow_remap(ip, &irec);
+       /* If there is a hole at end_fsb - 1 go to the previous extent */
+       if (eof || got.br_startoff > end_fsb) {
+               ASSERT(idx > 0);
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, --idx), &got);
+       }
 
-               /*
-                * We can have a hole in the CoW fork if part of a directio
-                * write is CoW but part of it isn't.
-                */
-               rlen = ilen = irec.br_blockcount;
-               if (irec.br_startblock == HOLESTARTBLOCK)
+       /* Walk backwards until we're out of the I/O range... */
+       while (got.br_startoff + got.br_blockcount > offset_fsb) {
+               del = got;
+               xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb);
+
+               /* Extent delete may have bumped idx forward */
+               if (!del.br_blockcount) {
+                       idx--;
                        goto next_extent;
+               }
+
+               ASSERT(!isnullstartblock(got.br_startblock));
 
                /* Unmap the old blocks in the data fork. */
-               while (rlen) {
-                       xfs_defer_init(&dfops, &firstfsb);
-                       error = __xfs_bunmapi(tp, ip, irec.br_startoff,
-                                       &rlen, 0, 1, &firstfsb, &dfops);
-                       if (error)
-                               goto out_defer;
-
-                       /*
-                        * Trim the extent to whatever got unmapped.
-                        * Remember, bunmapi works backwards.
-                        */
-                       uirec.br_startblock = irec.br_startblock + rlen;
-                       uirec.br_startoff = irec.br_startoff + rlen;
-                       uirec.br_blockcount = irec.br_blockcount - rlen;
-                       irec.br_blockcount = rlen;
-                       trace_xfs_reflink_cow_remap_piece(ip, &uirec);
+               xfs_defer_init(&dfops, &firstfsb);
+               rlen = del.br_blockcount;
+               error = __xfs_bunmapi(tp, ip, del.br_startoff, &rlen, 0, 1,
+                               &firstfsb, &dfops);
+               if (error)
+                       goto out_defer;
 
-                       /* Free the CoW orphan record. */
-                       error = xfs_refcount_free_cow_extent(tp->t_mountp,
-                                       &dfops, uirec.br_startblock,
-                                       uirec.br_blockcount);
-                       if (error)
-                               goto out_defer;
+               /* Trim the extent to whatever got unmapped. */
+               if (rlen) {
+                       xfs_trim_extent(&del, del.br_startoff + rlen,
+                               del.br_blockcount - rlen);
+               }
+               trace_xfs_reflink_cow_remap(ip, &del);
 
-                       /* Map the new blocks into the data fork. */
-                       error = xfs_bmap_map_extent(tp->t_mountp, &dfops,
-                                       ip, &uirec);
-                       if (error)
-                               goto out_defer;
+               /* Free the CoW orphan record. */
+               error = xfs_refcount_free_cow_extent(tp->t_mountp, &dfops,
+                               del.br_startblock, del.br_blockcount);
+               if (error)
+                       goto out_defer;
 
-                       /* Remove the mapping from the CoW fork. */
-                       error = xfs_bunmapi_cow(ip, &uirec);
-                       if (error)
-                               goto out_defer;
+               /* Map the new blocks into the data fork. */
+               error = xfs_bmap_map_extent(tp->t_mountp, &dfops, ip, &del);
+               if (error)
+                       goto out_defer;
 
-                       error = xfs_defer_finish(&tp, &dfops, ip);
-                       if (error)
-                               goto out_defer;
-               }
+               /* Remove the mapping from the CoW fork. */
+               xfs_bmap_del_extent_cow(ip, &idx, &got, &del);
+
+               error = xfs_defer_finish(&tp, &dfops, ip);
+               if (error)
+                       goto out_defer;
 
 next_extent:
-               /* Roll on... */
-               offset_fsb = irec.br_startoff + ilen;
+               if (idx < 0)
+                       break;
+               xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got);
        }
 
        error = xfs_trans_commit(tp);
@@ -774,7 +737,6 @@ next_extent:
 
 out_defer:
        xfs_defer_cancel(&dfops);
-out_cancel:
        xfs_trans_cancel(tp);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
 out:
@@ -1312,19 +1274,26 @@ out_error:
  */
 int
 xfs_reflink_remap_range(
-       struct xfs_inode        *src,
-       xfs_off_t               srcoff,
-       struct xfs_inode        *dest,
-       xfs_off_t               destoff,
-       xfs_off_t               len,
-       unsigned int            flags)
+       struct file             *file_in,
+       loff_t                  pos_in,
+       struct file             *file_out,
+       loff_t                  pos_out,
+       u64                     len,
+       bool                    is_dedupe)
 {
+       struct inode            *inode_in = file_inode(file_in);
+       struct xfs_inode        *src = XFS_I(inode_in);
+       struct inode            *inode_out = file_inode(file_out);
+       struct xfs_inode        *dest = XFS_I(inode_out);
        struct xfs_mount        *mp = src->i_mount;
+       loff_t                  bs = inode_out->i_sb->s_blocksize;
+       bool                    same_inode = (inode_in == inode_out);
        xfs_fileoff_t           sfsbno, dfsbno;
        xfs_filblks_t           fsblen;
-       int                     error;
        xfs_extlen_t            cowextsize;
-       bool                    is_same;
+       loff_t                  isize;
+       ssize_t                 ret;
+       loff_t                  blen;
 
        if (!xfs_sb_version_hasreflink(&mp->m_sb))
                return -EOPNOTSUPP;
@@ -1332,17 +1301,8 @@ xfs_reflink_remap_range(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       /* Don't reflink realtime inodes */
-       if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest))
-               return -EINVAL;
-
-       if (flags & ~XFS_REFLINK_ALL)
-               return -EINVAL;
-
-       trace_xfs_reflink_remap_range(src, srcoff, len, dest, destoff);
-
        /* Lock both files against IO */
-       if (src->i_ino == dest->i_ino) {
+       if (same_inode) {
                xfs_ilock(src, XFS_IOLOCK_EXCL);
                xfs_ilock(src, XFS_MMAPLOCK_EXCL);
        } else {
@@ -1350,39 +1310,126 @@ xfs_reflink_remap_range(
                xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL);
        }
 
+       /* Don't touch certain kinds of inodes */
+       ret = -EPERM;
+       if (IS_IMMUTABLE(inode_out))
+               goto out_unlock;
+
+       ret = -ETXTBSY;
+       if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
+               goto out_unlock;
+
+
+       /* Don't reflink dirs, pipes, sockets... */
+       ret = -EISDIR;
+       if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
+               goto out_unlock;
+       ret = -EINVAL;
+       if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode))
+               goto out_unlock;
+       if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
+               goto out_unlock;
+
+       /* Don't reflink realtime inodes */
+       if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest))
+               goto out_unlock;
+
+       /* Don't share DAX file data for now. */
+       if (IS_DAX(inode_in) || IS_DAX(inode_out))
+               goto out_unlock;
+
+       /* Are we going all the way to the end? */
+       isize = i_size_read(inode_in);
+       if (isize == 0) {
+               ret = 0;
+               goto out_unlock;
+       }
+
+       if (len == 0)
+               len = isize - pos_in;
+
+       /* Ensure offsets don't wrap and the input is inside i_size */
+       if (pos_in + len < pos_in || pos_out + len < pos_out ||
+           pos_in + len > isize)
+               goto out_unlock;
+
+       /* Don't allow dedupe past EOF in the dest file */
+       if (is_dedupe) {
+               loff_t  disize;
+
+               disize = i_size_read(inode_out);
+               if (pos_out >= disize || pos_out + len > disize)
+                       goto out_unlock;
+       }
+
+       /* If we're linking to EOF, continue to the block boundary. */
+       if (pos_in + len == isize)
+               blen = ALIGN(isize, bs) - pos_in;
+       else
+               blen = len;
+
+       /* Only reflink if we're aligned to block boundaries */
+       if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) ||
+           !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs))
+               goto out_unlock;
+
+       /* Don't allow overlapped reflink within the same file */
+       if (same_inode) {
+               if (pos_out + blen > pos_in && pos_out < pos_in + blen)
+                       goto out_unlock;
+       }
+
+       /* Wait for the completion of any pending IOs on both files */
+       inode_dio_wait(inode_in);
+       if (!same_inode)
+               inode_dio_wait(inode_out);
+
+       ret = filemap_write_and_wait_range(inode_in->i_mapping,
+                       pos_in, pos_in + len - 1);
+       if (ret)
+               goto out_unlock;
+
+       ret = filemap_write_and_wait_range(inode_out->i_mapping,
+                       pos_out, pos_out + len - 1);
+       if (ret)
+               goto out_unlock;
+
+       trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);
+
        /*
         * Check that the extents are the same.
         */
-       if (flags & XFS_REFLINK_DEDUPE) {
-               is_same = false;
-               error = xfs_compare_extents(VFS_I(src), srcoff, VFS_I(dest),
-                               destoff, len, &is_same);
-               if (error)
-                       goto out_error;
+       if (is_dedupe) {
+               bool            is_same = false;
+
+               ret = xfs_compare_extents(inode_in, pos_in, inode_out, pos_out,
+                               len, &is_same);
+               if (ret)
+                       goto out_unlock;
                if (!is_same) {
-                       error = -EBADE;
-                       goto out_error;
+                       ret = -EBADE;
+                       goto out_unlock;
                }
        }
 
-       error = xfs_reflink_set_inode_flag(src, dest);
-       if (error)
-               goto out_error;
+       ret = xfs_reflink_set_inode_flag(src, dest);
+       if (ret)
+               goto out_unlock;
 
        /*
         * Invalidate the page cache so that we can clear any CoW mappings
         * in the destination file.
         */
-       truncate_inode_pages_range(&VFS_I(dest)->i_data, destoff,
-                                  PAGE_ALIGN(destoff + len) - 1);
+       truncate_inode_pages_range(&inode_out->i_data, pos_out,
+                                  PAGE_ALIGN(pos_out + len) - 1);
 
-       dfsbno = XFS_B_TO_FSBT(mp, destoff);
-       sfsbno = XFS_B_TO_FSBT(mp, srcoff);
+       dfsbno = XFS_B_TO_FSBT(mp, pos_out);
+       sfsbno = XFS_B_TO_FSBT(mp, pos_in);
        fsblen = XFS_B_TO_FSB(mp, len);
-       error = xfs_reflink_remap_blocks(src, sfsbno, dest, dfsbno, fsblen,
-                       destoff + len);
-       if (error)
-               goto out_error;
+       ret = xfs_reflink_remap_blocks(src, sfsbno, dest, dfsbno, fsblen,
+                       pos_out + len);
+       if (ret)
+               goto out_unlock;
 
        /*
         * Carry the cowextsize hint from src to dest if we're sharing the
@@ -1390,26 +1437,24 @@ xfs_reflink_remap_range(
         * has a cowextsize hint, and the destination file does not.
         */
        cowextsize = 0;
-       if (srcoff == 0 && len == i_size_read(VFS_I(src)) &&
+       if (pos_in == 0 && len == i_size_read(inode_in) &&
            (src->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) &&
-           destoff == 0 && len >= i_size_read(VFS_I(dest)) &&
+           pos_out == 0 && len >= i_size_read(inode_out) &&
            !(dest->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE))
                cowextsize = src->i_d.di_cowextsize;
 
-       error = xfs_reflink_update_dest(dest, destoff + len, cowextsize);
-       if (error)
-               goto out_error;
+       ret = xfs_reflink_update_dest(dest, pos_out + len, cowextsize);
 
-out_error:
+out_unlock:
        xfs_iunlock(src, XFS_MMAPLOCK_EXCL);
        xfs_iunlock(src, XFS_IOLOCK_EXCL);
        if (src->i_ino != dest->i_ino) {
                xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
                xfs_iunlock(dest, XFS_IOLOCK_EXCL);
        }
-       if (error)
-               trace_xfs_reflink_remap_range_error(dest, error, _RET_IP_);
-       return error;
+       if (ret)
+               trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
+       return ret;
 }
 
 /*
index 5dc3c8ac12aa5bef547904ca5dbe48275d63bc34..fad11607c9adf3937d6fa739c2ede29c7d0a8bb2 100644 (file)
@@ -26,8 +26,8 @@ extern int xfs_reflink_find_shared(struct xfs_mount *mp, xfs_agnumber_t agno,
 extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip,
                struct xfs_bmbt_irec *irec, bool *shared, bool *trimmed);
 
-extern int xfs_reflink_reserve_cow_range(struct xfs_inode *ip,
-               xfs_off_t offset, xfs_off_t count);
+extern int xfs_reflink_reserve_cow(struct xfs_inode *ip,
+               struct xfs_bmbt_irec *imap, bool *shared);
 extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip,
                xfs_off_t offset, xfs_off_t count);
 extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset,
@@ -43,11 +43,8 @@ extern int xfs_reflink_cancel_cow_range(struct xfs_inode *ip, xfs_off_t offset,
 extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset,
                xfs_off_t count);
 extern int xfs_reflink_recover_cow(struct xfs_mount *mp);
-#define XFS_REFLINK_DEDUPE     1       /* only reflink if contents match */
-#define XFS_REFLINK_ALL                (XFS_REFLINK_DEDUPE)
-extern int xfs_reflink_remap_range(struct xfs_inode *src, xfs_off_t srcoff,
-               struct xfs_inode *dest, xfs_off_t destoff, xfs_off_t len,
-               unsigned int flags);
+extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in,
+               struct file *file_out, loff_t pos_out, u64 len, bool is_dedupe);
 extern int xfs_reflink_clear_inode_flag(struct xfs_inode *ip,
                struct xfs_trans **tpp);
 extern int xfs_reflink_unshare(struct xfs_inode *ip, xfs_off_t offset,
index 5f8d55d29a11cc4a4db2e30f55766acbeed78b33..276d3023d60f8201b635ae1f0c2ccbf26aac74fd 100644 (file)
@@ -512,13 +512,13 @@ static struct attribute *xfs_error_attrs[] = {
 };
 
 
-struct kobj_type xfs_error_cfg_ktype = {
+static struct kobj_type xfs_error_cfg_ktype = {
        .release = xfs_sysfs_release,
        .sysfs_ops = &xfs_sysfs_ops,
        .default_attrs = xfs_error_attrs,
 };
 
-struct kobj_type xfs_error_ktype = {
+static struct kobj_type xfs_error_ktype = {
        .release = xfs_sysfs_release,
        .sysfs_ops = &xfs_sysfs_ops,
 };
index ad188d3a83f3739db19ed8af577fe4259c9267e8..0907752be62d3de9e385890550a8e92f0402b398 100644 (file)
@@ -3346,7 +3346,7 @@ DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_alloc);
 DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_found);
 DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_enospc);
 
-DEFINE_RW_EVENT(xfs_reflink_reserve_cow_range);
+DEFINE_RW_EVENT(xfs_reflink_reserve_cow);
 DEFINE_RW_EVENT(xfs_reflink_allocate_cow_range);
 
 DEFINE_INODE_IREC_EVENT(xfs_reflink_bounce_dio_write);
@@ -3356,9 +3356,7 @@ DEFINE_INODE_IREC_EVENT(xfs_reflink_trim_irec);
 DEFINE_SIMPLE_IO_EVENT(xfs_reflink_cancel_cow_range);
 DEFINE_SIMPLE_IO_EVENT(xfs_reflink_end_cow);
 DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap);
-DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap_piece);
 
-DEFINE_INODE_ERROR_EVENT(xfs_reflink_reserve_cow_range_error);
 DEFINE_INODE_ERROR_EVENT(xfs_reflink_allocate_cow_range_error);
 DEFINE_INODE_ERROR_EVENT(xfs_reflink_cancel_cow_range_error);
 DEFINE_INODE_ERROR_EVENT(xfs_reflink_end_cow_error);
index 1b949e08015ccd936f5a99bcf868ed30c7f78f26..c19700e2a2fe25d169a64180593438d9815c3f77 100644 (file)
@@ -230,72 +230,62 @@ struct acpi_table_facs {
 /* Fields common to all versions of the FADT */
 
 struct acpi_table_fadt {
-       struct acpi_table_header header;        /* [V1] Common ACPI table header */
-       u32 facs;               /* [V1] 32-bit physical address of FACS */
-       u32 dsdt;               /* [V1] 32-bit physical address of DSDT */
-       u8 model;               /* [V1] System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */
-       u8 preferred_profile;   /* [V1] Conveys preferred power management profile to OSPM. */
-       u16 sci_interrupt;      /* [V1] System vector of SCI interrupt */
-       u32 smi_command;        /* [V1] 32-bit Port address of SMI command port */
-       u8 acpi_enable;         /* [V1] Value to write to SMI_CMD to enable ACPI */
-       u8 acpi_disable;        /* [V1] Value to write to SMI_CMD to disable ACPI */
-       u8 s4_bios_request;     /* [V1] Value to write to SMI_CMD to enter S4BIOS state */
-       u8 pstate_control;      /* [V1] Processor performance state control */
-       u32 pm1a_event_block;   /* [V1] 32-bit port address of Power Mgt 1a Event Reg Blk */
-       u32 pm1b_event_block;   /* [V1] 32-bit port address of Power Mgt 1b Event Reg Blk */
-       u32 pm1a_control_block; /* [V1] 32-bit port address of Power Mgt 1a Control Reg Blk */
-       u32 pm1b_control_block; /* [V1] 32-bit port address of Power Mgt 1b Control Reg Blk */
-       u32 pm2_control_block;  /* [V1] 32-bit port address of Power Mgt 2 Control Reg Blk */
-       u32 pm_timer_block;     /* [V1] 32-bit port address of Power Mgt Timer Ctrl Reg Blk */
-       u32 gpe0_block;         /* [V1] 32-bit port address of General Purpose Event 0 Reg Blk */
-       u32 gpe1_block;         /* [V1] 32-bit port address of General Purpose Event 1 Reg Blk */
-       u8 pm1_event_length;    /* [V1] Byte Length of ports at pm1x_event_block */
-       u8 pm1_control_length;  /* [V1] Byte Length of ports at pm1x_control_block */
-       u8 pm2_control_length;  /* [V1] Byte Length of ports at pm2_control_block */
-       u8 pm_timer_length;     /* [V1] Byte Length of ports at pm_timer_block */
-       u8 gpe0_block_length;   /* [V1] Byte Length of ports at gpe0_block */
-       u8 gpe1_block_length;   /* [V1] Byte Length of ports at gpe1_block */
-       u8 gpe1_base;           /* [V1] Offset in GPE number space where GPE1 events start */
-       u8 cst_control;         /* [V1] Support for the _CST object and C-States change notification */
-       u16 c2_latency;         /* [V1] Worst case HW latency to enter/exit C2 state */
-       u16 c3_latency;         /* [V1] Worst case HW latency to enter/exit C3 state */
-       u16 flush_size;         /* [V1] Processor memory cache line width, in bytes */
-       u16 flush_stride;       /* [V1] Number of flush strides that need to be read */
-       u8 duty_offset;         /* [V1] Processor duty cycle index in processor P_CNT reg */
-       u8 duty_width;          /* [V1] Processor duty cycle value bit width in P_CNT register */
-       u8 day_alarm;           /* [V1] Index to day-of-month alarm in RTC CMOS RAM */
-       u8 month_alarm;         /* [V1] Index to month-of-year alarm in RTC CMOS RAM */
-       u8 century;             /* [V1] Index to century in RTC CMOS RAM */
-       u16 boot_flags;         /* [V3] IA-PC Boot Architecture Flags (see below for individual flags) */
-       u8 reserved;            /* [V1] Reserved, must be zero */
-       u32 flags;              /* [V1] Miscellaneous flag bits (see below for individual flags) */
-       /* End of Version 1 FADT fields (ACPI 1.0) */
-
-       struct acpi_generic_address reset_register;     /* [V3] 64-bit address of the Reset register */
-       u8 reset_value;         /* [V3] Value to write to the reset_register port to reset the system */
-       u16 arm_boot_flags;     /* [V5] ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */
-       u8 minor_revision;      /* [V5] FADT Minor Revision (ACPI 5.1) */
-       u64 Xfacs;              /* [V3] 64-bit physical address of FACS */
-       u64 Xdsdt;              /* [V3] 64-bit physical address of DSDT */
-       struct acpi_generic_address xpm1a_event_block;  /* [V3] 64-bit Extended Power Mgt 1a Event Reg Blk address */
-       struct acpi_generic_address xpm1b_event_block;  /* [V3] 64-bit Extended Power Mgt 1b Event Reg Blk address */
-       struct acpi_generic_address xpm1a_control_block;        /* [V3] 64-bit Extended Power Mgt 1a Control Reg Blk address */
-       struct acpi_generic_address xpm1b_control_block;        /* [V3] 64-bit Extended Power Mgt 1b Control Reg Blk address */
-       struct acpi_generic_address xpm2_control_block; /* [V3] 64-bit Extended Power Mgt 2 Control Reg Blk address */
-       struct acpi_generic_address xpm_timer_block;    /* [V3] 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */
-       struct acpi_generic_address xgpe0_block;        /* [V3] 64-bit Extended General Purpose Event 0 Reg Blk address */
-       struct acpi_generic_address xgpe1_block;        /* [V3] 64-bit Extended General Purpose Event 1 Reg Blk address */
-       /* End of Version 3 FADT fields (ACPI 2.0) */
-
-       struct acpi_generic_address sleep_control;      /* [V4] 64-bit Sleep Control register (ACPI 5.0) */
-       /* End of Version 4 FADT fields (ACPI 3.0 and ACPI 4.0) (Field was originally reserved in ACPI 3.0) */
-
-       struct acpi_generic_address sleep_status;       /* [V5] 64-bit Sleep Status register (ACPI 5.0) */
-       /* End of Version 5 FADT fields (ACPI 5.0) */
-
-       u64 hypervisor_id;      /* [V6] Hypervisor Vendor ID (ACPI 6.0) */
-       /* End of Version 6 FADT fields (ACPI 6.0) */
-
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 facs;               /* 32-bit physical address of FACS */
+       u32 dsdt;               /* 32-bit physical address of DSDT */
+       u8 model;               /* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */
+       u8 preferred_profile;   /* Conveys preferred power management profile to OSPM. */
+       u16 sci_interrupt;      /* System vector of SCI interrupt */
+       u32 smi_command;        /* 32-bit Port address of SMI command port */
+       u8 acpi_enable;         /* Value to write to SMI_CMD to enable ACPI */
+       u8 acpi_disable;        /* Value to write to SMI_CMD to disable ACPI */
+       u8 s4_bios_request;     /* Value to write to SMI_CMD to enter S4BIOS state */
+       u8 pstate_control;      /* Processor performance state control */
+       u32 pm1a_event_block;   /* 32-bit port address of Power Mgt 1a Event Reg Blk */
+       u32 pm1b_event_block;   /* 32-bit port address of Power Mgt 1b Event Reg Blk */
+       u32 pm1a_control_block; /* 32-bit port address of Power Mgt 1a Control Reg Blk */
+       u32 pm1b_control_block; /* 32-bit port address of Power Mgt 1b Control Reg Blk */
+       u32 pm2_control_block;  /* 32-bit port address of Power Mgt 2 Control Reg Blk */
+       u32 pm_timer_block;     /* 32-bit port address of Power Mgt Timer Ctrl Reg Blk */
+       u32 gpe0_block;         /* 32-bit port address of General Purpose Event 0 Reg Blk */
+       u32 gpe1_block;         /* 32-bit port address of General Purpose Event 1 Reg Blk */
+       u8 pm1_event_length;    /* Byte Length of ports at pm1x_event_block */
+       u8 pm1_control_length;  /* Byte Length of ports at pm1x_control_block */
+       u8 pm2_control_length;  /* Byte Length of ports at pm2_control_block */
+       u8 pm_timer_length;     /* Byte Length of ports at pm_timer_block */
+       u8 gpe0_block_length;   /* Byte Length of ports at gpe0_block */
+       u8 gpe1_block_length;   /* Byte Length of ports at gpe1_block */
+       u8 gpe1_base;           /* Offset in GPE number space where GPE1 events start */
+       u8 cst_control;         /* Support for the _CST object and C-States change notification */
+       u16 c2_latency;         /* Worst case HW latency to enter/exit C2 state */
+       u16 c3_latency;         /* Worst case HW latency to enter/exit C3 state */
+       u16 flush_size;         /* Processor memory cache line width, in bytes */
+       u16 flush_stride;       /* Number of flush strides that need to be read */
+       u8 duty_offset;         /* Processor duty cycle index in processor P_CNT reg */
+       u8 duty_width;          /* Processor duty cycle value bit width in P_CNT register */
+       u8 day_alarm;           /* Index to day-of-month alarm in RTC CMOS RAM */
+       u8 month_alarm;         /* Index to month-of-year alarm in RTC CMOS RAM */
+       u8 century;             /* Index to century in RTC CMOS RAM */
+       u16 boot_flags;         /* IA-PC Boot Architecture Flags (see below for individual flags) */
+       u8 reserved;            /* Reserved, must be zero */
+       u32 flags;              /* Miscellaneous flag bits (see below for individual flags) */
+       struct acpi_generic_address reset_register;     /* 64-bit address of the Reset register */
+       u8 reset_value;         /* Value to write to the reset_register port to reset the system */
+       u16 arm_boot_flags;     /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */
+       u8 minor_revision;      /* FADT Minor Revision (ACPI 5.1) */
+       u64 Xfacs;              /* 64-bit physical address of FACS */
+       u64 Xdsdt;              /* 64-bit physical address of DSDT */
+       struct acpi_generic_address xpm1a_event_block;  /* 64-bit Extended Power Mgt 1a Event Reg Blk address */
+       struct acpi_generic_address xpm1b_event_block;  /* 64-bit Extended Power Mgt 1b Event Reg Blk address */
+       struct acpi_generic_address xpm1a_control_block;        /* 64-bit Extended Power Mgt 1a Control Reg Blk address */
+       struct acpi_generic_address xpm1b_control_block;        /* 64-bit Extended Power Mgt 1b Control Reg Blk address */
+       struct acpi_generic_address xpm2_control_block; /* 64-bit Extended Power Mgt 2 Control Reg Blk address */
+       struct acpi_generic_address xpm_timer_block;    /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */
+       struct acpi_generic_address xgpe0_block;        /* 64-bit Extended General Purpose Event 0 Reg Blk address */
+       struct acpi_generic_address xgpe1_block;        /* 64-bit Extended General Purpose Event 1 Reg Blk address */
+       struct acpi_generic_address sleep_control;      /* 64-bit Sleep Control register (ACPI 5.0) */
+       struct acpi_generic_address sleep_status;       /* 64-bit Sleep Status register (ACPI 5.0) */
+       u64 hypervisor_id;      /* Hypervisor Vendor ID (ACPI 6.0) */
 };
 
 /* Masks for FADT IA-PC Boot Architecture Flags (boot_flags) [Vx]=Introduced in this FADT revision */
@@ -311,8 +301,8 @@ struct acpi_table_fadt {
 
 /* Masks for FADT ARM Boot Architecture Flags (arm_boot_flags) ACPI 5.1 */
 
-#define ACPI_FADT_PSCI_COMPLIANT    (1)        /* 00: [V5] PSCI 0.2+ is implemented */
-#define ACPI_FADT_PSCI_USE_HVC      (1<<1)     /* 01: [V5] HVC must be used instead of SMC as the PSCI conduit */
+#define ACPI_FADT_PSCI_COMPLIANT    (1)        /* 00: [V5+] PSCI 0.2+ is implemented */
+#define ACPI_FADT_PSCI_USE_HVC      (1<<1)     /* 01: [V5+] HVC must be used instead of SMC as the PSCI conduit */
 
 /* Masks for FADT flags */
 
@@ -409,34 +399,20 @@ struct acpi_table_desc {
  * match the expected length. In other words, the length of the
  * FADT is the bottom line as to what the version really is.
  *
- * NOTE: There is no officialy released V2 of the FADT. This
- * version was used only for prototyping and testing during the
- * 32-bit to 64-bit transition. V3 was the first official 64-bit
- * version of the FADT.
- *
- * Update this list of defines when a new version of the FADT is
- * added to the ACPI specification. Note that the FADT version is
- * only incremented when new fields are appended to the existing
- * version. Therefore, the FADT version is competely independent
- * from the version of the ACPI specification where it is
- * defined.
- *
- * For reference, the various FADT lengths are as follows:
- *     FADT V1 size: 0x074      ACPI 1.0
- *     FADT V3 size: 0x0F4      ACPI 2.0
- *     FADT V4 size: 0x100      ACPI 3.0 and ACPI 4.0
- *     FADT V5 size: 0x10C      ACPI 5.0
- *     FADT V6 size: 0x114      ACPI 6.0
+ * For reference, the values below are as follows:
+ *     FADT V1 size: 0x074
+ *     FADT V2 size: 0x084
+ *     FADT V3 size: 0x0F4
+ *     FADT V4 size: 0x0F4
+ *     FADT V5 size: 0x10C
+ *     FADT V6 size: 0x114
  */
-#define ACPI_FADT_V1_SIZE       (u32) (ACPI_FADT_OFFSET (flags) + 4)   /* ACPI 1.0 */
-#define ACPI_FADT_V3_SIZE       (u32) (ACPI_FADT_OFFSET (sleep_control))       /* ACPI 2.0 */
-#define ACPI_FADT_V4_SIZE       (u32) (ACPI_FADT_OFFSET (sleep_status))        /* ACPI 3.0 and ACPI 4.0 */
-#define ACPI_FADT_V5_SIZE       (u32) (ACPI_FADT_OFFSET (hypervisor_id))       /* ACPI 5.0 */
-#define ACPI_FADT_V6_SIZE       (u32) (sizeof (struct acpi_table_fadt))        /* ACPI 6.0 */
-
-/* Update these when new FADT versions are added */
+#define ACPI_FADT_V1_SIZE       (u32) (ACPI_FADT_OFFSET (flags) + 4)
+#define ACPI_FADT_V2_SIZE       (u32) (ACPI_FADT_OFFSET (minor_revision) + 1)
+#define ACPI_FADT_V3_SIZE       (u32) (ACPI_FADT_OFFSET (sleep_control))
+#define ACPI_FADT_V5_SIZE       (u32) (ACPI_FADT_OFFSET (hypervisor_id))
+#define ACPI_FADT_V6_SIZE       (u32) (sizeof (struct acpi_table_fadt))
 
-#define ACPI_FADT_MAX_VERSION   6
 #define ACPI_FADT_CONFORMANCE   "ACPI 6.1 (FADT version 6)"
 
 #endif                         /* __ACTBL_H__ */
index 17a940a1447716420d076be01e3402eb314bafb0..8caa79c617035e60a41ee850150d2b472f35df5a 100644 (file)
@@ -21,7 +21,7 @@ extern void pcc_mbox_free_channel(struct mbox_chan *chan);
 static inline struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
                                                         int subspace_id)
 {
-       return NULL;
+       return ERR_PTR(-ENODEV);
 }
 static inline void pcc_mbox_free_channel(struct mbox_chan *chan) { }
 #endif
index a5d98d171866fe758462b15898f5e04019fe57cb..e861a24f06f2aca2bb575a10fa3041fcb32815e3 100644 (file)
 #ifndef __init
 #define __init
 #endif
+#ifndef __iomem
+#define __iomem
+#endif
 
 /* Host-dependent types and defines for user-space ACPICA */
 
index 43199a049da5f1a4d4129c9575f6c5dff1c199d1..63554e9f6e0c68595943e27d2734ad4fa8271007 100644 (file)
@@ -70,7 +70,7 @@ KSYM(__kcrctab_\name):
 #include <generated/autoksyms.h>
 
 #define __EXPORT_SYMBOL(sym, val, sec)                         \
-       __cond_export_sym(sym, val, sec, config_enabled(__KSYM_##sym))
+       __cond_export_sym(sym, val, sec, __is_defined(__KSYM_##sym))
 #define __cond_export_sym(sym, val, sec, conf)                 \
        ___cond_export_sym(sym, val, sec, conf)
 #define ___cond_export_sym(sym, val, sec, enabled)             \
index 40e887068da213e595951f16caf8eb7ca83d3179..0504ef8f3aa31d5e7a9f0d86d1cb3fc130fee9e0 100644 (file)
@@ -118,9 +118,9 @@ do {                                                                        \
 #define this_cpu_generic_read(pcp)                                     \
 ({                                                                     \
        typeof(pcp) __ret;                                              \
-       preempt_disable();                                              \
+       preempt_disable_notrace();                                      \
        __ret = raw_cpu_generic_read(pcp);                              \
-       preempt_enable();                                               \
+       preempt_enable_notrace();                                       \
        __ret;                                                          \
 })
 
index af0254c0942476f67e92c08f8e75918e529b4994..4df64a1fc09e7aab7f88cd4afe73928228930147 100644 (file)
@@ -14,6 +14,8 @@
  * [_sdata, _edata]: contains .data.* sections, may also contain .rodata.*
  *                   and/or .init.* sections.
  * [__start_rodata, __end_rodata]: contains .rodata.* sections
+ * [__start_data_ro_after_init, __end_data_ro_after_init]:
+ *                  contains data.ro_after_init section
  * [__init_begin, __init_end]: contains .init.* sections, but .init.text.*
  *                   may be out of this range on some architectures.
  * [_sinittext, _einittext]: contains .init.text.* sections
@@ -31,6 +33,7 @@ extern char _data[], _sdata[], _edata[];
 extern char __bss_start[], __bss_stop[];
 extern char __init_begin[], __init_end[];
 extern char _sinittext[], _einittext[];
+extern char __start_data_ro_after_init[], __end_data_ro_after_init[];
 extern char _end[];
 extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[];
 extern char __kprobes_text_start[], __kprobes_text_end[];
index 30747960bc54a29496eb134ebff26bfcb67e2fd7..31e1d639abedacd87828613416bce5c459694fc8 100644 (file)
  * own by defining an empty RO_AFTER_INIT_DATA.
  */
 #ifndef RO_AFTER_INIT_DATA
-#define RO_AFTER_INIT_DATA *(.data..ro_after_init)
+#define RO_AFTER_INIT_DATA                                             \
+       __start_data_ro_after_init = .;                                 \
+       *(.data..ro_after_init)                                         \
+       __end_data_ro_after_init = .;
 #endif
 
 /*
index 61580b19f9f6e1e31e42fc6afcd0f416cc2c5f2a..22f884c97387e9929a4fb19e7ee5328bccb34c8d 100644 (file)
@@ -124,6 +124,8 @@ struct drbg_state {
        struct skcipher_request *ctr_req;       /* CTR mode request handle */
        __u8 *ctr_null_value_buf;               /* CTR mode unaligned buffer */
        __u8 *ctr_null_value;                   /* CTR mode aligned zero buf */
+       __u8 *outscratchpadbuf;                 /* CTR mode output scratchpad */
+        __u8 *outscratchpad;                   /* CTR mode aligned outbuf */
        struct completion ctr_completion;       /* CTR mode async handler */
        int ctr_async_err;                      /* CTR mode async error */
 
index 43cf193e54d666be087c5962ac82401f0db3782e..8b4dc62470ffae3df724e7efacd67553220a7d3f 100644 (file)
@@ -47,8 +47,14 @@ struct drm_crtc;
  * @src_h: height of visible portion of plane (in 16.16)
  * @rotation: rotation of the plane
  * @zpos: priority of the given plane on crtc (optional)
+ *     Note that multiple active planes on the same crtc can have an identical
+ *     zpos value. The rule to solving the conflict is to compare the plane
+ *     object IDs; the plane with a higher ID must be stacked on top of a
+ *     plane with a lower ID.
  * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1
- *     where N is the number of active planes for given crtc
+ *     where N is the number of active planes for given crtc. Note that
+ *     the driver must call drm_atomic_normalize_zpos() to update this before
+ *     it can be trusted.
  * @src: clipped source coordinates of the plane (in 16.16)
  * @dst: clipped destination coordinates of the plane
  * @visible: visibility of the plane
diff --git a/include/dt-bindings/sound/cs42l42.h b/include/dt-bindings/sound/cs42l42.h
new file mode 100644 (file)
index 0000000..399a123
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * cs42l42.h -- CS42L42 ALSA SoC audio driver DT bindings header
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.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 __DT_CS42L42_H
+#define __DT_CS42L42_H
+
+/* HPOUT Load Capacity */
+#define CS42L42_HPOUT_LOAD_1NF         0
+#define CS42L42_HPOUT_LOAD_10NF                1
+
+/* HPOUT Clamp to GND Overide */
+#define CS42L42_HPOUT_CLAMP_EN         0
+#define CS42L42_HPOUT_CLAMP_DIS                1
+
+/* Tip Sense Inversion */
+#define CS42L42_TS_INV_DIS                     0
+#define CS42L42_TS_INV_EN                      1
+
+/* Tip Sense Debounce */
+#define CS42L42_TS_DBNCE_0                     0
+#define CS42L42_TS_DBNCE_125                   1
+#define CS42L42_TS_DBNCE_250                   2
+#define CS42L42_TS_DBNCE_500                   3
+#define CS42L42_TS_DBNCE_750                   4
+#define CS42L42_TS_DBNCE_1000                  5
+#define CS42L42_TS_DBNCE_1250                  6
+#define CS42L42_TS_DBNCE_1500                  7
+
+/* Button Press Software Debounce Times */
+#define CS42L42_BTN_DET_INIT_DBNCE_MIN         0
+#define CS42L42_BTN_DET_INIT_DBNCE_DEFAULT     100
+#define CS42L42_BTN_DET_INIT_DBNCE_MAX         200
+
+#define CS42L42_BTN_DET_EVENT_DBNCE_MIN                0
+#define CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT    10
+#define CS42L42_BTN_DET_EVENT_DBNCE_MAX                20
+
+/* Button Detect Level Sensitivities */
+#define CS42L42_NUM_BIASES             4
+
+#define CS42L42_HS_DET_LEVEL_15                0x0F
+#define CS42L42_HS_DET_LEVEL_8         0x08
+#define CS42L42_HS_DET_LEVEL_4         0x04
+#define CS42L42_HS_DET_LEVEL_1         0x01
+
+#define CS42L42_HS_DET_LEVEL_MIN       0
+#define CS42L42_HS_DET_LEVEL_MAX       0x3F
+
+/* HS Bias Ramp Rate */
+
+#define CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL                0
+#define CS42L42_HSBIAS_RAMP_FAST                       1
+#define CS42L42_HSBIAS_RAMP_SLOW                       2
+#define CS42L42_HSBIAS_RAMP_SLOWEST                    3
+
+#define CS42L42_HSBIAS_RAMP_TIME0                      10
+#define CS42L42_HSBIAS_RAMP_TIME1                      40
+#define CS42L42_HSBIAS_RAMP_TIME2                      90
+#define CS42L42_HSBIAS_RAMP_TIME3                      170
+
+#endif /* __DT_CS42L42_H */
index ddbeda6dbdc87b4121617631efa0f1a486d1b6e2..61a3d90f32b338a030c3a064b50c403a48464293 100644 (file)
@@ -326,6 +326,7 @@ struct pci_dev;
 int acpi_pci_irq_enable (struct pci_dev *dev);
 void acpi_penalize_isa_irq(int irq, int active);
 bool acpi_isa_irq_available(int irq);
+void acpi_penalize_sci_irq(int irq, int trigger, int polarity);
 void acpi_pci_irq_disable (struct pci_dev *dev);
 
 extern int ec_read(u8 addr, u8 *val);
@@ -554,7 +555,8 @@ int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
 int acpi_device_modalias(struct device *, char *, int);
 void acpi_walk_dep_device_list(acpi_handle handle);
 
-struct platform_device *acpi_create_platform_device(struct acpi_device *);
+struct platform_device *acpi_create_platform_device(struct acpi_device *,
+                                                   struct property_entry *);
 #define ACPI_PTR(_ptr) (_ptr)
 
 static inline void acpi_device_set_enumerated(struct acpi_device *adev)
index 7035b997aaa57d7955f4d06501804cd09d8ed675..6aaf425cebc39a9dbb3619d7ad28987ca54a01c7 100644 (file)
@@ -14,7 +14,7 @@
   * are obviously wrong for any sort of memory access.
   */
 #define BPF_REGISTER_MAX_RANGE (1024 * 1024 * 1024)
-#define BPF_REGISTER_MIN_RANGE -(1024 * 1024 * 1024)
+#define BPF_REGISTER_MIN_RANGE -1
 
 struct bpf_reg_state {
        enum bpf_reg_type type;
@@ -22,7 +22,8 @@ struct bpf_reg_state {
         * Used to determine if any memory access using this register will
         * result in a bad access.
         */
-       u64 min_value, max_value;
+       s64 min_value;
+       u64 max_value;
        union {
                /* valid when type == CONST_IMM | PTR_TO_STACK | UNKNOWN_VALUE */
                s64 imm;
index 96337b15a60d59cd12e342b101d70efc1cd380d1..a8e66344bacc225642acc872c614b3017c314218 100644 (file)
@@ -258,6 +258,8 @@ struct ceph_watch_item {
        struct ceph_entity_addr addr;
 };
 
+#define CEPH_LINGER_ID_START   0xffff000000000000ULL
+
 struct ceph_osd_client {
        struct ceph_client     *client;
 
index af596381fa0fa05862bb836a02deaeea29fb9fa2..a428aec36aceeb22da48e9d3d755d2423e71969b 100644 (file)
@@ -785,7 +785,7 @@ extern struct of_device_id __clk_of_table;
  * routines, one at of_clk_init(), and one at platform device probe
  */
 #define CLK_OF_DECLARE_DRIVER(name, compat, fn) \
-       static void name##_of_clk_init_driver(struct device_node *np)   \
+       static void __init name##_of_clk_init_driver(struct device_node *np) \
        {                                                               \
                of_node_clear_flag(np, OF_POPULATED);                   \
                fn(np);                                                 \
index 432f5c97e18f4f75fd68b1c1101cf828fb3d4fa0..928e5ca0caee271e849fabeff0fa522a59650cc6 100644 (file)
 #endif
 #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP && !__CHECKER__ */
 
-#if GCC_VERSION >= 50000
+#if GCC_VERSION >= 70000
+#define KASAN_ABI_VERSION 5
+#elif GCC_VERSION >= 50000
 #define KASAN_ABI_VERSION 4
 #elif GCC_VERSION >= 40902
 #define KASAN_ABI_VERSION 3
index 3672809234a728ea9e7779b0456cbd57647d7150..d530c4627e54ef1091be820a78d3616166ca8906 100644 (file)
@@ -173,12 +173,6 @@ static inline void console_sysfs_notify(void)
 #endif
 extern bool console_suspend_enabled;
 
-#ifdef CONFIG_OF
-extern void console_set_by_of(void);
-#else
-static inline void console_set_by_of(void) {}
-#endif
-
 /* Suspend and resume console messages over PM events */
 extern void suspend_console(void);
 extern void resume_console(void);
index 5fa55fc56e18d1971da8c2e031c35a17fe0d51fc..32dc0cbd51ca3729bef594f7a84832bc6389e3ea 100644 (file)
@@ -677,10 +677,10 @@ static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy,
                if (best == table - 1)
                        return pos - table;
 
-               return best - pos;
+               return best - table;
        }
 
-       return best - pos;
+       return best - table;
 }
 
 /* Works only on sorted freq-tables */
index 9b207a8c5af3cedecc545dbf179464f32af4c4d0..afe641c02dca3320f3bf4255092deafeb77d536f 100644 (file)
@@ -81,6 +81,7 @@ enum cpuhp_state {
        CPUHP_AP_ARM_ARCH_TIMER_STARTING,
        CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
        CPUHP_AP_DUMMY_TIMER_STARTING,
+       CPUHP_AP_JCORE_TIMER_STARTING,
        CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
        CPUHP_AP_ARM_TWD_STARTING,
        CPUHP_AP_METAG_TIMER_STARTING,
index c46d2aa16d81221c240ec46cf5c7fec6dbfe4bdd..1d18af0345543aaecbfc46a04230735c2b0b0cf7 100644 (file)
@@ -106,8 +106,9 @@ static inline void frontswap_invalidate_area(unsigned type)
 
 static inline void frontswap_init(unsigned type, unsigned long *map)
 {
-       if (frontswap_enabled())
-               __frontswap_init(type, map);
+#ifdef CONFIG_FRONTSWAP
+       __frontswap_init(type, map);
+#endif
 }
 
 #endif /* _LINUX_FRONTSWAP_H */
index 16d2b6e874d679597478e653f3ef23974e0c33de..dc0478c07b2abd3887d7f5b1b84818a4ee24162e 100644 (file)
@@ -321,6 +321,7 @@ struct writeback_control;
 #define IOCB_HIPRI             (1 << 3)
 #define IOCB_DSYNC             (1 << 4)
 #define IOCB_SYNC              (1 << 5)
+#define IOCB_WRITE             (1 << 6)
 
 struct kiocb {
        struct file             *ki_filp;
@@ -1709,7 +1710,6 @@ struct file_operations {
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
        int (*fsync) (struct file *, loff_t, loff_t, int datasync);
-       int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
index 9b9f65d9987393d456911f41eacb4bdfa9fe0284..e35e6de633b9a7bc2a080d6b3596aa16e8c8582f 100644 (file)
@@ -22,7 +22,7 @@ extern int mincore_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                        unsigned char *vec);
 extern bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
                         unsigned long new_addr, unsigned long old_end,
-                        pmd_t *old_pmd, pmd_t *new_pmd);
+                        pmd_t *old_pmd, pmd_t *new_pmd, bool *need_flush);
 extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                        unsigned long addr, pgprot_t newprot,
                        int prot_numa);
index 6824556d37ed2cd4fb60e7aacd74f594986880c3..cd184bdca58fdc28e0ae59432445248c588fd2fc 100644 (file)
@@ -1169,13 +1169,6 @@ int __must_check __vmbus_driver_register(struct hv_driver *hv_driver,
                                         const char *mod_name);
 void vmbus_driver_unregister(struct hv_driver *hv_driver);
 
-static inline const char *vmbus_dev_name(const struct hv_device *device_obj)
-{
-       const struct kobject *kobj = &device_obj->device.kobj;
-
-       return kobj->name;
-}
-
 void vmbus_hvsock_device_unregister(struct vmbus_channel *channel);
 
 int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
index 2d9b650047a5b96582f66dff2b2581cce97c2b65..d49e26c6cdc7b5e48e41591f7c73e74d200441a8 100644 (file)
@@ -429,6 +429,7 @@ struct intel_iommu {
        struct page_req_dsc *prq;
        unsigned char prq_name[16];    /* Name for PRQ interrupt */
        struct idr pasid_idr;
+       u32 pasid_max;
 #endif
        struct q_inval  *qi;            /* Queued invalidation info */
        u32 *iommu_state; /* Store iommu states between suspend and resume.*/
index e2c8419278c192fd8002ae0b470ea2421dc51a57..82ef36eac8a16a8fc2b7b021f345910ac04b04b4 100644 (file)
@@ -141,4 +141,26 @@ enum {
 void *memremap(resource_size_t offset, size_t size, unsigned long flags);
 void memunmap(void *addr);
 
+/*
+ * On x86 PAT systems we have memory tracking that keeps track of
+ * the allowed mappings on memory ranges. This tracking works for
+ * all the in-kernel mapping APIs (ioremap*), but where the user
+ * wishes to map a range from a physical device into user memory
+ * the tracking won't be updated. This API is to be used by
+ * drivers which remap physical device pages into userspace,
+ * and wants to make sure they are mapped WC and not UC.
+ */
+#ifndef arch_io_reserve_memtype_wc
+static inline int arch_io_reserve_memtype_wc(resource_size_t base,
+                                            resource_size_t size)
+{
+       return 0;
+}
+
+static inline void arch_io_free_memtype_wc(resource_size_t base,
+                                          resource_size_t size)
+{
+}
+#endif
+
 #endif /* _LINUX_IO_H */
index e63e288dee836c5c81d88909550ee1155eb160b2..7892f55a1866db26d5c4edabf69a59606a2efa3f 100644 (file)
@@ -19,11 +19,15 @@ struct vm_fault;
 #define IOMAP_UNWRITTEN        0x04    /* blocks allocated @blkno in unwritten state */
 
 /*
- * Flags for iomap mappings:
+ * Flags for all iomap mappings:
  */
-#define IOMAP_F_MERGED 0x01    /* contains multiple blocks/extents */
-#define IOMAP_F_SHARED 0x02    /* block shared with another file */
-#define IOMAP_F_NEW    0x04    /* blocks have been newly allocated */
+#define IOMAP_F_NEW    0x01    /* blocks have been newly allocated */
+
+/*
+ * Flags that only need to be reported for IOMAP_REPORT requests:
+ */
+#define IOMAP_F_MERGED 0x10    /* contains multiple blocks/extents */
+#define IOMAP_F_SHARED 0x20    /* block shared with another file */
 
 /*
  * Magic value for blkno:
@@ -42,8 +46,9 @@ struct iomap {
 /*
  * Flags for iomap_begin / iomap_end.  No flag implies a read.
  */
-#define IOMAP_WRITE            (1 << 0)
-#define IOMAP_ZERO             (1 << 1)
+#define IOMAP_WRITE            (1 << 0) /* writing, must allocate blocks */
+#define IOMAP_ZERO             (1 << 1) /* zeroing operation, may skip holes */
+#define IOMAP_REPORT           (1 << 2) /* report extent status, e.g. FIEMAP */
 
 struct iomap_ops {
        /*
index 7e9a789be5e0df0198fbebcded35f1d90bc8a650..a0649973ee5b395641e4cbaf0861f93a328640c9 100644 (file)
@@ -123,12 +123,12 @@ struct inet6_skb_parm {
 };
 
 #if defined(CONFIG_NET_L3_MASTER_DEV)
-static inline bool skb_l3mdev_slave(__u16 flags)
+static inline bool ipv6_l3mdev_skb(__u16 flags)
 {
        return flags & IP6SKB_L3SLAVE;
 }
 #else
-static inline bool skb_l3mdev_slave(__u16 flags)
+static inline bool ipv6_l3mdev_skb(__u16 flags)
 {
        return false;
 }
@@ -139,11 +139,22 @@ static inline bool skb_l3mdev_slave(__u16 flags)
 
 static inline int inet6_iif(const struct sk_buff *skb)
 {
-       bool l3_slave = skb_l3mdev_slave(IP6CB(skb)->flags);
+       bool l3_slave = ipv6_l3mdev_skb(IP6CB(skb)->flags);
 
        return l3_slave ? skb->skb_iif : IP6CB(skb)->iif;
 }
 
+/* can not be used in TCP layer after tcp_v6_fill_cb */
+static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb)
+{
+#if defined(CONFIG_NET_L3_MASTER_DEV)
+       if (!net->ipv4.sysctl_tcp_l3mdev_accept &&
+           skb && ipv6_l3mdev_skb(IP6CB(skb)->flags))
+               return true;
+#endif
+       return false;
+}
+
 struct tcp6_request_sock {
        struct tcp_request_sock   tcp6rsk_tcp;
 };
index 8361c8d3edd10d8ae050f491d07cff180f407f35..b7e34313cdfe4a68fee46334158d7d22111993e9 100644 (file)
 #define GITS_BASER_TYPE_SHIFT                  (56)
 #define GITS_BASER_TYPE(r)             (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT            (48)
-#define GITS_BASER_ENTRY_SIZE(r)       ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
+#define GITS_BASER_ENTRY_SIZE(r)       ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
 #define GITS_BASER_SHAREABILITY_SHIFT  (10)
 #define GITS_BASER_InnerShareable                                      \
        GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)
index d600303306eb7b54bbc68b62c89243e778f2a75c..820c0ad54a0117596e63bae6845b1ebd771c3412 100644 (file)
@@ -44,6 +44,7 @@ static inline void kasan_disable_current(void)
 void kasan_unpoison_shadow(const void *address, size_t size);
 
 void kasan_unpoison_task_stack(struct task_struct *task);
+void kasan_unpoison_stack_above_sp_to(const void *watermark);
 
 void kasan_alloc_pages(struct page *page, unsigned int order);
 void kasan_free_pages(struct page *page, unsigned int order);
@@ -85,6 +86,7 @@ size_t kasan_metadata_size(struct kmem_cache *cache);
 static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
 
 static inline void kasan_unpoison_task_stack(struct task_struct *task) {}
+static inline void kasan_unpoison_stack_above_sp_to(const void *watermark) {}
 
 static inline void kasan_enable_current(void) {}
 static inline void kasan_disable_current(void) {}
index 15ec117ec5373e8c98ac801d433e67a8aa11e974..8f2e059e4d45559b54c1fbd087181865beac7af7 100644 (file)
@@ -31,7 +31,6 @@
  * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
  * the last step cherry picks the 2nd arg, we get a zero.
  */
-#define config_enabled(cfg)            ___is_defined(cfg)
 #define __is_defined(x)                        ___is_defined(x)
 #define ___is_defined(val)             ____is_defined(__ARG_PLACEHOLDER_##val)
 #define ____is_defined(arg1_or_junk)   __take_second_arg(arg1_or_junk 1, 0)
  * otherwise. For boolean options, this is equivalent to
  * IS_ENABLED(CONFIG_FOO).
  */
-#define IS_BUILTIN(option) config_enabled(option)
+#define IS_BUILTIN(option) __is_defined(option)
 
 /*
  * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
  * otherwise.
  */
-#define IS_MODULE(option) config_enabled(option##_MODULE)
+#define IS_MODULE(option) __is_defined(option##_MODULE)
 
 /*
  * IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled
index f4947fda11e771c35c6465d3b329a8611249ee8b..8458c5351e562e57ea1161fc5ab234d5e53a47bb 100644 (file)
@@ -143,7 +143,7 @@ u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
                const struct nd_cmd_desc *desc, int idx, void *buf);
 u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
                const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
-               const u32 *out_field);
+               const u32 *out_field, unsigned long remainder);
 int nvdimm_bus_check_dimm_count(struct nvdimm_bus *nvdimm_bus, int dimm_count);
 struct nd_region *nvdimm_pmem_region_create(struct nvdimm_bus *nvdimm_bus,
                struct nd_region_desc *ndr_desc);
index f6a16429735812f678f96595dff75e603504a8af..c9f379689dd068beadbdb828fe8f09b521b28f12 100644 (file)
@@ -476,7 +476,6 @@ enum {
 enum {
        MLX4_INTERFACE_STATE_UP         = 1 << 0,
        MLX4_INTERFACE_STATE_DELETION   = 1 << 1,
-       MLX4_INTERFACE_STATE_SHUTDOWN   = 1 << 2,
 };
 
 #define MSTR_SM_CHANGE_MASK (MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK | \
@@ -1399,7 +1398,8 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
                    u32 *lkey, u32 *rkey);
 int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
 int mlx4_SYNC_TPT(struct mlx4_dev *dev);
-int mlx4_test_interrupts(struct mlx4_dev *dev);
+int mlx4_test_interrupt(struct mlx4_dev *dev, int vector);
+int mlx4_test_async(struct mlx4_dev *dev);
 int mlx4_query_diag_counters(struct mlx4_dev *dev, u8 op_modifier,
                             const u32 offset[], u32 value[],
                             size_t array_len, u8 port);
index 85c4786427e49686f5adedeb962e67dfbc375616..ecc451d89ccd8c68edb8ab4051224d44b9568668 100644 (file)
@@ -418,8 +418,12 @@ struct mlx5_core_health {
        u32                             prev;
        int                             miss_counter;
        bool                            sick;
+       /* wq spinlock to synchronize draining */
+       spinlock_t                      wq_lock;
        struct workqueue_struct        *wq;
+       unsigned long                   flags;
        struct work_struct              work;
+       struct delayed_work             recover_work;
 };
 
 struct mlx5_cq_table {
@@ -625,10 +629,6 @@ struct mlx5_db {
        int                     index;
 };
 
-enum {
-       MLX5_DB_PER_PAGE = PAGE_SIZE / L1_CACHE_BYTES,
-};
-
 enum {
        MLX5_COMP_EQ_SIZE = 1024,
 };
@@ -638,13 +638,6 @@ enum {
        MLX5_PTYS_EN = 1 << 2,
 };
 
-struct mlx5_db_pgdir {
-       struct list_head        list;
-       DECLARE_BITMAP(bitmap, MLX5_DB_PER_PAGE);
-       __be32                 *db_page;
-       dma_addr_t              db_dma;
-};
-
 typedef void (*mlx5_cmd_cbk_t)(int status, void *context);
 
 struct mlx5_cmd_work_ent {
@@ -789,6 +782,7 @@ void mlx5_health_cleanup(struct mlx5_core_dev *dev);
 int mlx5_health_init(struct mlx5_core_dev *dev);
 void mlx5_start_health_poll(struct mlx5_core_dev *dev);
 void mlx5_stop_health_poll(struct mlx5_core_dev *dev);
+void mlx5_drain_health_wq(struct mlx5_core_dev *dev);
 int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size,
                        struct mlx5_buf *buf, int node);
 int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf);
index e9caec6a51e97a618ff5ab9b76dd6371708564e8..a92c8d73aeafc5f5bafa551eacc284f86bad50d0 100644 (file)
@@ -1266,29 +1266,25 @@ static inline int fixup_user_fault(struct task_struct *tsk,
 }
 #endif
 
-extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
+extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len,
+               unsigned int gup_flags);
 extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-               void *buf, int len, int write);
+               void *buf, int len, unsigned int gup_flags);
 
-long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
-                     unsigned long start, unsigned long nr_pages,
-                     unsigned int foll_flags, struct page **pages,
-                     struct vm_area_struct **vmas, int *nonblocking);
 long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
                            unsigned long start, unsigned long nr_pages,
-                           int write, int force, struct page **pages,
+                           unsigned int gup_flags, struct page **pages,
                            struct vm_area_struct **vmas);
 long get_user_pages(unsigned long start, unsigned long nr_pages,
-                           int write, int force, struct page **pages,
+                           unsigned int gup_flags, struct page **pages,
                            struct vm_area_struct **vmas);
 long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
-                   int write, int force, struct page **pages, int *locked);
+                   unsigned int gup_flags, struct page **pages, int *locked);
 long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
                               unsigned long start, unsigned long nr_pages,
-                              int write, int force, struct page **pages,
-                              unsigned int gup_flags);
+                              struct page **pages, unsigned int gup_flags);
 long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
-                   int write, int force, struct page **pages);
+                   struct page **pages, unsigned int gup_flags);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                        struct page **pages);
 
@@ -1306,7 +1302,7 @@ struct frame_vector {
 struct frame_vector *frame_vector_create(unsigned int nr_frames);
 void frame_vector_destroy(struct frame_vector *vec);
 int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
-                    bool write, bool force, struct frame_vector *vec);
+                    unsigned int gup_flags, struct frame_vector *vec);
 void put_vaddr_frames(struct frame_vector *vec);
 int frame_vector_to_pages(struct frame_vector *vec);
 void frame_vector_to_pfns(struct frame_vector *vec);
@@ -1391,7 +1387,7 @@ static inline int stack_guard_page_end(struct vm_area_struct *vma,
                !vma_growsup(vma->vm_next, addr);
 }
 
-int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t);
+int vma_is_stack_for_current(struct vm_area_struct *vma);
 
 extern unsigned long move_page_tables(struct vm_area_struct *vma,
                unsigned long old_addr, struct vm_area_struct *new_vma,
@@ -2232,6 +2228,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,
 #define FOLL_TRIED     0x800   /* a retry, previous pass started an IO */
 #define FOLL_MLOCK     0x1000  /* lock present pages */
 #define FOLL_REMOTE    0x2000  /* we are working on non-current tsk/mm */
+#define FOLL_COW       0x4000  /* internal GUP flag */
 
 typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
                        void *data);
index 7f2ae99e5daf39406fa5b166f6a1a75c464d1fcd..0f088f3a2fed8df6435819a52360940310272462 100644 (file)
@@ -440,33 +440,7 @@ struct zone {
        seqlock_t               span_seqlock;
 #endif
 
-       /*
-        * wait_table           -- the array holding the hash table
-        * wait_table_hash_nr_entries   -- the size of the hash table array
-        * wait_table_bits      -- wait_table_size == (1 << wait_table_bits)
-        *
-        * The purpose of all these is to keep track of the people
-        * waiting for a page to become available and make them
-        * runnable again when possible. The trouble is that this
-        * consumes a lot of space, especially when so few things
-        * wait on pages at a given time. So instead of using
-        * per-page waitqueues, we use a waitqueue hash table.
-        *
-        * The bucket discipline is to sleep on the same queue when
-        * colliding and wake all in that wait queue when removing.
-        * When something wakes, it must check to be sure its page is
-        * truly available, a la thundering herd. The cost of a
-        * collision is great, but given the expected load of the
-        * table, they should be so rare as to be outweighed by the
-        * benefits from the saved space.
-        *
-        * __wait_on_page_locked() and unlock_page() in mm/filemap.c, are the
-        * primary users of these fields, and in mm/page_alloc.c
-        * free_area_init_core() performs the initialization of them.
-        */
-       wait_queue_head_t       *wait_table;
-       unsigned long           wait_table_hash_nr_entries;
-       unsigned long           wait_table_bits;
+       int initialized;
 
        /* Write-intensive fields used from the page allocator */
        ZONE_PADDING(_pad1_)
@@ -546,7 +520,7 @@ static inline bool zone_spans_pfn(const struct zone *zone, unsigned long pfn)
 
 static inline bool zone_is_initialized(struct zone *zone)
 {
-       return !!zone->wait_table;
+       return zone->initialized;
 }
 
 static inline bool zone_is_empty(struct zone *zone)
index c5d3d5024fc8584aa22e99dd8b0fd5da75e7bf19..d8905a229f34833a4336b0a69431a4a0a94bc76e 100644 (file)
@@ -1184,7 +1184,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
                           int page);
 
 /* Reset and initialize a NAND device */
-int nand_reset(struct nand_chip *chip);
+int nand_reset(struct nand_chip *chip, int chipnr);
 
 /* Free resources held by the NAND device */
 void nand_cleanup(struct nand_chip *chip);
index 136ae6bbe81e12f769b38776ccbceac9f151360e..e16a2a980ea8d83ad6462c6f3d742f9683018195 100644 (file)
@@ -1619,7 +1619,7 @@ enum netdev_priv_flags {
  *     @dcbnl_ops:     Data Center Bridging netlink ops
  *     @num_tc:        Number of traffic classes in the net device
  *     @tc_to_txq:     XXX: need comments on this one
- *     @prio_tc_map    XXX: need comments on this one
+ *     @prio_tc_map:   XXX: need comments on this one
  *
  *     @fcoe_ddp_xid:  Max exchange id for FCoE LRO by ddp
  *
@@ -2169,7 +2169,10 @@ struct napi_gro_cb {
        /* Used to determine if flush_id can be ignored */
        u8      is_atomic:1;
 
-       /* 5 bit hole */
+       /* Number of gro_receive callbacks this packet already went through */
+       u8 recursion_counter:4;
+
+       /* 1 bit hole */
 
        /* used to support CHECKSUM_COMPLETE for tunneling protocols */
        __wsum  csum;
@@ -2180,6 +2183,40 @@ struct napi_gro_cb {
 
 #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
 
+#define GRO_RECURSION_LIMIT 15
+static inline int gro_recursion_inc_test(struct sk_buff *skb)
+{
+       return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT;
+}
+
+typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff *);
+static inline struct sk_buff **call_gro_receive(gro_receive_t cb,
+                                               struct sk_buff **head,
+                                               struct sk_buff *skb)
+{
+       if (unlikely(gro_recursion_inc_test(skb))) {
+               NAPI_GRO_CB(skb)->flush |= 1;
+               return NULL;
+       }
+
+       return cb(head, skb);
+}
+
+typedef struct sk_buff **(*gro_receive_sk_t)(struct sock *, struct sk_buff **,
+                                            struct sk_buff *);
+static inline struct sk_buff **call_gro_receive_sk(gro_receive_sk_t cb,
+                                                  struct sock *sk,
+                                                  struct sk_buff **head,
+                                                  struct sk_buff *skb)
+{
+       if (unlikely(gro_recursion_inc_test(skb))) {
+               NAPI_GRO_CB(skb)->flush |= 1;
+               return NULL;
+       }
+
+       return cb(sk, head, skb);
+}
+
 struct packet_type {
        __be16                  type;   /* This is really htons(ether_type). */
        struct net_device       *dev;   /* NULL is wildcarded here           */
@@ -3317,6 +3354,21 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 bool is_skb_forwardable(const struct net_device *dev,
                        const struct sk_buff *skb);
 
+static __always_inline int ____dev_forward_skb(struct net_device *dev,
+                                              struct sk_buff *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;
+       }
+
+       skb_scrub_packet(skb, true);
+       skb->priority = 0;
+       return 0;
+}
+
 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
 
 extern int             netdev_budget;
@@ -3877,7 +3929,7 @@ struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
             ldev = netdev_all_lower_get_next(dev, &(iter)))
 
 #define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \
-       for (iter = (dev)->all_adj_list.lower.next, \
+       for (iter = &(dev)->all_adj_list.lower, \
             ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \
             ldev; \
             ldev = netdev_all_lower_get_next_rcu(dev, &(iter)))
index 7676557ce357d682c3c47f0599e66bdd8a42225f..fc3c2420659395039be1288a82e8d62d98aefab3 100644 (file)
@@ -16,7 +16,6 @@
 #define _LINUX_NVME_H
 
 #include <linux/types.h>
-#include <linux/uuid.h>
 
 /* NQN names in commands fields specified one size */
 #define NVMF_NQN_FIELD_LEN     256
@@ -182,7 +181,7 @@ struct nvme_id_ctrl {
        char                    fr[8];
        __u8                    rab;
        __u8                    ieee[3];
-       __u8                    mic;
+       __u8                    cmic;
        __u8                    mdts;
        __le16                  cntlid;
        __le32                  ver;
@@ -202,7 +201,13 @@ struct nvme_id_ctrl {
        __u8                    apsta;
        __le16                  wctemp;
        __le16                  cctemp;
-       __u8                    rsvd270[50];
+       __le16                  mtfa;
+       __le32                  hmpre;
+       __le32                  hmmin;
+       __u8                    tnvmcap[16];
+       __u8                    unvmcap[16];
+       __le32                  rpmbs;
+       __u8                    rsvd316[4];
        __le16                  kas;
        __u8                    rsvd322[190];
        __u8                    sqes;
@@ -267,7 +272,7 @@ struct nvme_id_ns {
        __le16                  nabo;
        __le16                  nabspf;
        __u16                   rsvd46;
-       __le64                  nvmcap[2];
+       __u8                    nvmcap[16];
        __u8                    rsvd64[40];
        __u8                    nguid[16];
        __u8                    eui64[8];
@@ -276,6 +281,16 @@ struct nvme_id_ns {
        __u8                    vs[3712];
 };
 
+enum {
+       NVME_ID_CNS_NS                  = 0x00,
+       NVME_ID_CNS_CTRL                = 0x01,
+       NVME_ID_CNS_NS_ACTIVE_LIST      = 0x02,
+       NVME_ID_CNS_NS_PRESENT_LIST     = 0x10,
+       NVME_ID_CNS_NS_PRESENT          = 0x11,
+       NVME_ID_CNS_CTRL_NS_LIST        = 0x12,
+       NVME_ID_CNS_CTRL_LIST           = 0x13,
+};
+
 enum {
        NVME_NS_FEAT_THIN       = 1 << 0,
        NVME_NS_FLBAS_LBA_MASK  = 0xf,
@@ -556,8 +571,10 @@ enum nvme_admin_opcode {
        nvme_admin_set_features         = 0x09,
        nvme_admin_get_features         = 0x0a,
        nvme_admin_async_event          = 0x0c,
+       nvme_admin_ns_mgmt              = 0x0d,
        nvme_admin_activate_fw          = 0x10,
        nvme_admin_download_fw          = 0x11,
+       nvme_admin_ns_attach            = 0x15,
        nvme_admin_keep_alive           = 0x18,
        nvme_admin_format_nvm           = 0x80,
        nvme_admin_security_send        = 0x81,
@@ -583,6 +600,7 @@ enum {
        NVME_FEAT_WRITE_ATOMIC  = 0x0a,
        NVME_FEAT_ASYNC_EVENT   = 0x0b,
        NVME_FEAT_AUTO_PST      = 0x0c,
+       NVME_FEAT_HOST_MEM_BUF  = 0x0d,
        NVME_FEAT_KATO          = 0x0f,
        NVME_FEAT_SW_PROGRESS   = 0x80,
        NVME_FEAT_HOST_ID       = 0x81,
@@ -745,7 +763,7 @@ struct nvmf_common_command {
 struct nvmf_disc_rsp_page_entry {
        __u8            trtype;
        __u8            adrfam;
-       __u8            nqntype;
+       __u8            subtype;
        __u8            treq;
        __le16          portid;
        __le16          cntlid;
@@ -794,7 +812,7 @@ struct nvmf_connect_command {
 };
 
 struct nvmf_connect_data {
-       uuid_be         hostid;
+       __u8            hostid[16];
        __le16          cntlid;
        char            resv4[238];
        char            subsysnqn[NVMF_NQN_FIELD_LEN];
@@ -905,12 +923,23 @@ enum {
        NVME_SC_INVALID_VECTOR          = 0x108,
        NVME_SC_INVALID_LOG_PAGE        = 0x109,
        NVME_SC_INVALID_FORMAT          = 0x10a,
-       NVME_SC_FIRMWARE_NEEDS_RESET    = 0x10b,
+       NVME_SC_FW_NEEDS_CONV_RESET     = 0x10b,
        NVME_SC_INVALID_QUEUE           = 0x10c,
        NVME_SC_FEATURE_NOT_SAVEABLE    = 0x10d,
        NVME_SC_FEATURE_NOT_CHANGEABLE  = 0x10e,
        NVME_SC_FEATURE_NOT_PER_NS      = 0x10f,
-       NVME_SC_FW_NEEDS_RESET_SUBSYS   = 0x110,
+       NVME_SC_FW_NEEDS_SUBSYS_RESET   = 0x110,
+       NVME_SC_FW_NEEDS_RESET          = 0x111,
+       NVME_SC_FW_NEEDS_MAX_TIME       = 0x112,
+       NVME_SC_FW_ACIVATE_PROHIBITED   = 0x113,
+       NVME_SC_OVERLAPPING_RANGE       = 0x114,
+       NVME_SC_NS_INSUFFICENT_CAP      = 0x115,
+       NVME_SC_NS_ID_UNAVAILABLE       = 0x116,
+       NVME_SC_NS_ALREADY_ATTACHED     = 0x118,
+       NVME_SC_NS_IS_PRIVATE           = 0x119,
+       NVME_SC_NS_NOT_ATTACHED         = 0x11a,
+       NVME_SC_THIN_PROV_NOT_SUPP      = 0x11b,
+       NVME_SC_CTRL_LIST_INVALID       = 0x11c,
 
        /*
         * I/O Command Set Specific - NVM commands:
@@ -941,6 +970,7 @@ enum {
        NVME_SC_REFTAG_CHECK            = 0x284,
        NVME_SC_COMPARE_FAILED          = 0x285,
        NVME_SC_ACCESS_DENIED           = 0x286,
+       NVME_SC_UNWRITTEN_BLOCK         = 0x287,
 
        NVME_SC_DNR                     = 0x4000,
 };
@@ -960,6 +990,7 @@ struct nvme_completion {
        __le16  status;         /* did the command fail, and if so, why? */
 };
 
-#define NVME_VS(major, minor) (((major) << 16) | ((minor) << 8))
+#define NVME_VS(major, minor, tertiary) \
+       (((major) << 16) | ((minor) << 8) | (tertiary))
 
 #endif /* _LINUX_NVME_H */
index 2ab233661ae5da49cac59c33c38433501b1af4b4..a58cca8bcb29d8c9bdcda71538cfa8f25c913916 100644 (file)
@@ -29,6 +29,7 @@ struct phy_device *of_phy_attach(struct net_device *dev,
 extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np);
 extern int of_mdio_parse_addr(struct device *dev, const struct device_node *np);
 extern int of_phy_register_fixed_link(struct device_node *np);
+extern void of_phy_deregister_fixed_link(struct device_node *np);
 extern bool of_phy_is_fixed_link(struct device_node *np);
 
 #else /* CONFIG_OF */
@@ -83,6 +84,9 @@ static inline int of_phy_register_fixed_link(struct device_node *np)
 {
        return -ENOSYS;
 }
+static inline void of_phy_deregister_fixed_link(struct device_node *np)
+{
+}
 static inline bool of_phy_is_fixed_link(struct device_node *np)
 {
        return false;
index dd15d39e1985908614271dcb8e8712c4fffa4f63..7dbe9148b2f8a661257d0aa620cf1f61fa7d5f57 100644 (file)
@@ -374,16 +374,13 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
 }
 
 /*
- * Get the offset in PAGE_SIZE.
- * (TODO: hugepage should have ->index in PAGE_SIZE)
+ * Get index of the page with in radix-tree
+ * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE)
  */
-static inline pgoff_t page_to_pgoff(struct page *page)
+static inline pgoff_t page_to_index(struct page *page)
 {
        pgoff_t pgoff;
 
-       if (unlikely(PageHeadHuge(page)))
-               return page->index << compound_order(page);
-
        if (likely(!PageTransTail(page)))
                return page->index;
 
@@ -396,6 +393,18 @@ static inline pgoff_t page_to_pgoff(struct page *page)
        return pgoff;
 }
 
+/*
+ * Get the offset in PAGE_SIZE.
+ * (TODO: hugepage should have ->index in PAGE_SIZE)
+ */
+static inline pgoff_t page_to_pgoff(struct page *page)
+{
+       if (unlikely(PageHeadHuge(page)))
+               return page->index << compound_order(page);
+
+       return page_to_index(page);
+}
+
 /*
  * Return byte-offset into filesystem object for page.
  */
index 0e49f70dbd9b0aaf48d8546d2765f7c4fe813012..a38772a855885e48e0fc5a5f83c942efc9d9db4c 100644 (file)
@@ -1928,6 +1928,20 @@ static inline int pci_pcie_type(const struct pci_dev *dev)
        return (pcie_caps_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
 }
 
+static inline struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
+{
+       while (1) {
+               if (!pci_is_pcie(dev))
+                       break;
+               if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
+                       return dev;
+               if (!dev->bus->self)
+                       break;
+               dev = dev->bus->self;
+       }
+       return NULL;
+}
+
 void pci_request_acs(void);
 bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags);
 bool pci_acs_path_enabled(struct pci_dev *start,
index 060d0ede88df6dfc34fbfcd1e60629d8dce5373d..4741ecdb981743151b70afff63b10740dfaa4132 100644 (file)
@@ -1257,6 +1257,7 @@ extern u64 perf_swevent_set_period(struct perf_event *event);
 extern void perf_event_enable(struct perf_event *event);
 extern void perf_event_disable(struct perf_event *event);
 extern void perf_event_disable_local(struct perf_event *event);
+extern void perf_event_disable_inatomic(struct perf_event *event);
 extern void perf_event_task_tick(void);
 #else /* !CONFIG_PERF_EVENTS: */
 static inline void *
index ee1bed7dbfc634c5e490e00b694b5b170087decd..78bb0d7f6b11ac0a78e02eb35d12c9cbc0545a53 100644 (file)
@@ -253,6 +253,13 @@ static inline int phy_set_mode(struct phy *phy, enum phy_mode mode)
        return -ENOSYS;
 }
 
+static inline int phy_reset(struct phy *phy)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
 static inline int phy_get_bus_width(struct phy *phy)
 {
        return -ENOSYS;
index f9ae903bbb8445c8d44c8531f2ebd1a47cc05f25..8978a60371f4372160d1372510dad00b1c4a76ed 100644 (file)
@@ -146,6 +146,7 @@ enum qed_led_mode {
 #define DIRECT_REG_RD(reg_addr) readl((void __iomem *)(reg_addr))
 
 #define QED_COALESCE_MAX 0xFF
+#define QED_DEFAULT_RX_USECS 12
 
 /* forward */
 struct qed_dev;
index 99fbe6d55acb29dcb8fd39cdbb1f1f1f9c2bbe49..f48d64b0e2fb943a492981f30f3851ed77103711 100644 (file)
@@ -68,7 +68,7 @@ void qede_roce_unregister_driver(struct qedr_driver *drv);
 
 bool qede_roce_supported(struct qede_dev *dev);
 
-#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
+#if IS_ENABLED(CONFIG_QED_RDMA)
 int qede_roce_dev_add(struct qede_dev *dev);
 void qede_roce_dev_event_open(struct qede_dev *dev);
 void qede_roce_dev_event_close(struct qede_dev *dev);
index 9adc7b21903d3dc97987bbcdcd6caa7b449cecc6..f6673132431d09c3caa0c1394286fb310c93f9c1 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/list.h>
 #include <linux/rbtree.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/bug.h>
 #include <linux/lockdep.h>
@@ -116,22 +117,22 @@ struct reg_sequence {
 #define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_us) \
 ({ \
        ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
-       int ret; \
+       int pollret; \
        might_sleep_if(sleep_us); \
        for (;;) { \
-               ret = regmap_read((map), (addr), &(val)); \
-               if (ret) \
+               pollret = regmap_read((map), (addr), &(val)); \
+               if (pollret) \
                        break; \
                if (cond) \
                        break; \
                if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
-                       ret = regmap_read((map), (addr), &(val)); \
+                       pollret = regmap_read((map), (addr), &(val)); \
                        break; \
                } \
                if (sleep_us) \
                        usleep_range((sleep_us >> 2) + 1, sleep_us); \
        } \
-       ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+       pollret ?: ((cond) ? 0 : -ETIMEDOUT); \
 })
 
 #ifdef CONFIG_REGMAP
index 348f51b0ec92ed02e72a2060eedb03f37cd0995f..e9c009dc3a4a35a256731f37b3b44d3f05b317e4 100644 (file)
@@ -2567,6 +2567,7 @@ extern void sched_autogroup_create_attach(struct task_struct *p);
 extern void sched_autogroup_detach(struct task_struct *p);
 extern void sched_autogroup_fork(struct signal_struct *sig);
 extern void sched_autogroup_exit(struct signal_struct *sig);
+extern void sched_autogroup_exit_task(struct task_struct *p);
 #ifdef CONFIG_PROC_FS
 extern void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m);
 extern int proc_sched_autogroup_set_nice(struct task_struct *p, int nice);
@@ -2576,6 +2577,7 @@ static inline void sched_autogroup_create_attach(struct task_struct *p) { }
 static inline void sched_autogroup_detach(struct task_struct *p) { }
 static inline void sched_autogroup_fork(struct signal_struct *sig) { }
 static inline void sched_autogroup_exit(struct signal_struct *sig) { }
+static inline void sched_autogroup_exit_task(struct task_struct *p) { }
 #endif
 
 extern int yield_to(struct task_struct *p, bool preempt);
index 601258f6e62153f3814e2a38e4c21ad97fc7ee87..32810f279f8e4f097d678fb3bb587254f42d7a00 100644 (file)
@@ -936,6 +936,7 @@ struct sk_buff_fclones {
 
 /**
  *     skb_fclone_busy - check if fclone is busy
+ *     @sk: socket
  *     @skb: buffer
  *
  * Returns true if skb is a fast clone, and its clone is not freed.
index ab02a457da1fa8aea378889394730c708b03e89b..e5d19344037491651c6c80f6b310842ee5715126 100644 (file)
@@ -25,6 +25,7 @@ struct svc_xprt_ops {
        void            (*xpo_detach)(struct svc_xprt *);
        void            (*xpo_free)(struct svc_xprt *);
        int             (*xpo_secure_port)(struct svc_rqst *);
+       void            (*xpo_kill_temp_xprt)(struct svc_xprt *);
 };
 
 struct svc_xprt_class {
index 0d7abb8b7315ce3ab5162bc606c64337f3709d20..91a740f6b884236e3ed5771f01397f4647f3cd9d 100644 (file)
@@ -902,8 +902,5 @@ asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len,
                                  unsigned long prot, int pkey);
 asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
 asmlinkage long sys_pkey_free(int pkey);
-//asmlinkage long sys_pkey_get(int pkey, unsigned long flags);
-//asmlinkage long sys_pkey_set(int pkey, unsigned long access_rights,
-//                          unsigned long flags);
 
 #endif
index 45f004e9cc598c0e57f665ca3476b5a1d623b695..2873baf5372a7b1484888566725e2c4dc7368d26 100644 (file)
 struct timespec;
 struct compat_timespec;
 
-#ifdef CONFIG_THREAD_INFO_IN_TASK
-struct thread_info {
-       unsigned long           flags;          /* low level flags */
-};
-
-#define INIT_THREAD_INFO(tsk)                  \
-{                                              \
-       .flags          = 0,                    \
-}
-#endif
-
 #ifdef CONFIG_THREAD_INFO_IN_TASK
 #define current_thread_info() ((struct thread_info *)current)
 #endif
index 3a375d07d0dc0284441133228af266956ed94f89..00d232406f18dbd1b6c27d1d24ca4c417d200530 100644 (file)
@@ -81,7 +81,8 @@
 #define CDC_NCM_TIMER_INTERVAL_MAX             (U32_MAX / NSEC_PER_USEC)
 
 /* Driver flags */
-#define CDC_NCM_FLAG_NDP_TO_END        0x02            /* NDP is placed at end of frame */
+#define CDC_NCM_FLAG_NDP_TO_END                        0x02    /* NDP is placed at end of frame */
+#define CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE  0x04    /* Avoid altsetting toggle during init */
 
 #define cdc_ncm_comm_intf_is_mbim(x)  ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
                                       (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
index f2d0727879472451e0c2815fc68f90b66a4c388c..8f998afc138434f672ab28883287e463f60f4733 100644 (file)
@@ -174,6 +174,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex,
                      const struct in6_addr *addr);
 int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
                      const struct in6_addr *addr);
+void __ipv6_sock_mc_close(struct sock *sk);
 void ipv6_sock_mc_close(struct sock *sk);
 bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
                    const struct in6_addr *src_addr);
index f00bf667ec3399dd38850e048557c41fa7786dc6..554671c81f4a39a8a773a01a318af0b1c70b5617 100644 (file)
@@ -1018,7 +1018,7 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
 }
 
 struct hci_dev *hci_dev_get(int index);
-struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src);
+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, u8 src_type);
 
 struct hci_dev *hci_alloc_dev(void);
 void hci_free_dev(struct hci_dev *hdev);
index bd19faad0d9620026f7bf923a53ed9c4e4094f7d..14b51d739c3b39d5d9b8f0b934d3926841cdce69 100644 (file)
@@ -4046,6 +4046,18 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
  * that do not do the 802.11/802.3 conversion on the device.
  */
 
+/**
+ * ieee80211_data_to_8023_exthdr - convert an 802.11 data frame to 802.3
+ * @skb: the 802.11 data frame
+ * @ehdr: pointer to a &struct ethhdr that will get the header, instead
+ *     of it being pushed into the SKB
+ * @addr: the device MAC address
+ * @iftype: the virtual interface type
+ * Return: 0 on success. Non-zero on error.
+ */
+int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+                                 const u8 *addr, enum nl80211_iftype iftype);
+
 /**
  * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
  * @skb: the 802.11 data frame
@@ -4053,8 +4065,11 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
  * @iftype: the virtual interface type
  * Return: 0 on success. Non-zero on error.
  */
-int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
-                          enum nl80211_iftype iftype);
+static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
+                                        enum nl80211_iftype iftype)
+{
+       return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype);
+}
 
 /**
  * ieee80211_data_from_8023 - convert an 802.3 frame to 802.11
@@ -4072,22 +4087,23 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
 /**
  * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
  *
- * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of
- * 802.3 frames. The @list will be empty if the decode fails. The
- * @skb is consumed after the function returns.
+ * Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames.
+ * The @list will be empty if the decode fails. The @skb must be fully
+ * header-less before being passed in here; it is freed in this function.
  *
- * @skb: The input IEEE 802.11n A-MSDU frame.
+ * @skb: The input A-MSDU frame without any headers.
  * @list: The output list of 802.3 frames. It must be allocated and
  *     initialized by by the caller.
  * @addr: The device MAC address.
  * @iftype: The device interface type.
  * @extra_headroom: The hardware extra headroom for SKBs in the @list.
- * @has_80211_header: Set it true if SKB is with IEEE 802.11 header.
+ * @check_da: DA to check in the inner ethernet header, or NULL
+ * @check_sa: SA to check in the inner ethernet header, or NULL
  */
 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
                              const u8 *addr, enum nl80211_iftype iftype,
                              const unsigned int extra_headroom,
-                             bool has_80211_header);
+                             const u8 *check_da, const u8 *check_sa);
 
 /**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
index d15214d673b2e8e08fd6437b572278fb1359f10d..2a1abbf8da74368cd01adc40cef6c0644e059ef2 100644 (file)
@@ -68,6 +68,9 @@ static inline int gro_cells_init(struct gro_cells *gcells, struct net_device *de
                struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
 
                __skb_queue_head_init(&cell->napi_skbs);
+
+               set_bit(NAPI_STATE_NO_BUSY_POLL, &cell->napi.state);
+
                netif_napi_add(dev, &cell->napi, gro_cell_poll, 64);
                napi_enable(&cell->napi);
        }
index 515352c6280a45c6b1783ae4e10760b729b917d0..b0576cb2ab25dddf6fdfb6fd4327fdc24829b178 100644 (file)
@@ -190,8 +190,8 @@ struct inet6_dev {
        __u32                   if_flags;
        int                     dead;
 
+       u32                     desync_factor;
        u8                      rndid[8];
-       struct timer_list       regen_timer;
        struct list_head        tempaddr_list;
 
        struct in6_addr         token;
index bc43c0fcae122daea994a17843abcd84f6e6adb1..d3a107850a41f0b4b62fedd4d0b88b20a45166b2 100644 (file)
@@ -38,7 +38,7 @@ struct sock;
 struct inet_skb_parm {
        int                     iif;
        struct ip_options       opt;            /* Compiled IP options          */
-       unsigned char           flags;
+       u16                     flags;
 
 #define IPSKB_FORWARDED                BIT(0)
 #define IPSKB_XFRM_TUNNEL_SIZE BIT(1)
@@ -47,11 +47,16 @@ struct inet_skb_parm {
 #define IPSKB_REROUTED         BIT(4)
 #define IPSKB_DOREDIRECT       BIT(5)
 #define IPSKB_FRAG_PMTU                BIT(6)
-#define IPSKB_FRAG_SEGS                BIT(7)
+#define IPSKB_L3SLAVE          BIT(7)
 
        u16                     frag_max_size;
 };
 
+static inline bool ipv4_l3mdev_skb(u16 flags)
+{
+       return !!(flags & IPSKB_L3SLAVE);
+}
+
 static inline unsigned int ip_hdrlen(const struct sk_buff *skb)
 {
        return ip_hdr(skb)->ihl * 4;
@@ -572,7 +577,7 @@ int ip_options_rcv_srr(struct sk_buff *skb);
  */
 
 void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
-void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int offset);
+void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int tlen, int offset);
 int ip_cmsg_send(struct sock *sk, struct msghdr *msg,
                 struct ipcm_cookie *ipc, bool allow_ipv6);
 int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
@@ -594,7 +599,7 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport,
 
 static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
-       ip_cmsg_recv_offset(msg, skb, 0);
+       ip_cmsg_recv_offset(msg, skb, 0, 0);
 }
 
 bool icmp_global_allow(void);
index fb961a576abe4a62d02c69d6393abd91a2930fe1..a74e2aa40ef42d6e7edb917890164cce9f0fa835 100644 (file)
@@ -230,6 +230,8 @@ struct fib6_table {
        rwlock_t                tb6_lock;
        struct fib6_node        tb6_root;
        struct inet_peer_base   tb6_peers;
+       unsigned int            flags;
+#define RT6_TABLE_HAS_DFLT_ROUTER      BIT(0)
 };
 
 #define RT6_TABLE_UNSPEC       RT_TABLE_UNSPEC
index e0cd318d5103fb9a9a7be9ddfda40f8696925fcc..f83e78d071a30c332fc1bd20f5f187adfd8e0b64 100644 (file)
@@ -32,6 +32,7 @@ struct route_info {
 #define RT6_LOOKUP_F_SRCPREF_TMP       0x00000008
 #define RT6_LOOKUP_F_SRCPREF_PUBLIC    0x00000010
 #define RT6_LOOKUP_F_SRCPREF_COA       0x00000020
+#define RT6_LOOKUP_F_IGNORE_LINKSTATE  0x00000040
 
 /* We do not (yet ?) support IPv6 jumbograms (RFC 2675)
  * Unlike IPv4, hdr->seg_len doesn't include the IPv6 header
index 20ed9699fcd40be5362083fdbbf58d2da9420b44..1b1cf33cbfb02eaf4eb1eeb92be474076fdeebe4 100644 (file)
@@ -146,6 +146,7 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
 {
        int pkt_len, err;
 
+       memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
        pkt_len = skb->len - skb_inner_network_offset(skb);
        err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
        if (unlikely(net_xmit_eval(err)))
index b9314b48e39f32ef22366087673bcc961d196b43..f390c3bb05c5d2189d169d31038fd5cb991bebaa 100644 (file)
@@ -243,6 +243,7 @@ int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
                   struct netlink_callback *cb);
 int fib_table_flush(struct net *net, struct fib_table *table);
 struct fib_table *fib_trie_unmerge(struct fib_table *main_tb);
+void fib_table_flush_external(struct fib_table *table);
 void fib_free_table(struct fib_table *tb);
 
 #ifndef CONFIG_IP_MULTIPLE_TABLES
index 8fed1cd78658a6e088b63f7703290cb02c1969b6..f11ca837361b37f93f4061dcc8945c198be8b1f9 100644 (file)
@@ -970,6 +970,8 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
 int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
                           char __user *optval, int __user *optlen);
 
+int __ip6_datagram_connect(struct sock *sk, struct sockaddr *addr,
+                          int addr_len);
 int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len);
 int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *addr,
                                 int addr_len);
index a810dfcb83c2382cb7fe1954eba7bae1645e9046..e2dba93e374fda7f93c5dda34d28df8211e9eacc 100644 (file)
@@ -811,14 +811,18 @@ enum mac80211_rate_control_flags {
  * in the control information, and it will be filled by the rate
  * control algorithm according to what should be sent. For example,
  * if this array contains, in the format { <idx>, <count> } the
- * information
+ * information::
+ *
  *    { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 }
+ *
  * then this means that the frame should be transmitted
  * up to twice at rate 3, up to twice at rate 2, and up to four
  * times at rate 1 if it doesn't get acknowledged. Say it gets
  * acknowledged by the peer after the fifth attempt, the status
- * information should then contain
+ * information should then contain::
+ *
  *   { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ...
+ *
  * since it was transmitted twice at rate 3, twice at rate 2
  * and once at rate 1 after which we received an acknowledgement.
  */
@@ -1168,8 +1172,8 @@ enum mac80211_rx_vht_flags {
  * @rate_idx: index of data rate into band's supported rates or MCS index if
  *     HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
  * @vht_nss: number of streams (VHT only)
- * @flag: %RX_FLAG_*
- * @vht_flag: %RX_VHT_FLAG_*
+ * @flag: %RX_FLAG_\*
+ * @vht_flag: %RX_VHT_FLAG_\*
  * @rx_flags: internal RX flags for mac80211
  * @ampdu_reference: A-MPDU reference number, must be a different value for
  *     each A-MPDU but the same for each subframe within one A-MPDU
@@ -1432,7 +1436,7 @@ enum ieee80211_vif_flags {
  * @probe_req_reg: probe requests should be reported to mac80211 for this
  *     interface.
  * @drv_priv: data area for driver use, will always be aligned to
- *     sizeof(void *).
+ *     sizeof(void \*).
  * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
  */
 struct ieee80211_vif {
@@ -1743,7 +1747,7 @@ struct ieee80211_sta_rates {
  * @wme: indicates whether the STA supports QoS/WME (if local devices does,
  *     otherwise always false)
  * @drv_priv: data area for driver use, will always be aligned to
- *     sizeof(void *), size is determined in hw information.
+ *     sizeof(void \*), size is determined in hw information.
  * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
  *     if wme is supported.
  * @max_sp: max Service Period. Only valid if wme is supported.
@@ -2146,12 +2150,12 @@ enum ieee80211_hw_flags {
  *
  * @radiotap_mcs_details: lists which MCS information can the HW
  *     reports, by default it is set to _MCS, _GI and _BW but doesn't
- *     include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only
+ *     include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_\* values, only
  *     adding _BW is supported today.
  *
  * @radiotap_vht_details: lists which VHT MCS information the HW reports,
  *     the default is _GI | _BANDWIDTH.
- *     Use the %IEEE80211_RADIOTAP_VHT_KNOWN_* values.
+ *     Use the %IEEE80211_RADIOTAP_VHT_KNOWN_\* values.
  *
  * @radiotap_timestamp: Information for the radiotap timestamp field; if the
  *     'units_pos' member is set to a non-negative value it must be set to
@@ -2486,6 +2490,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * in the software stack cares about, we will, in the future, have mac80211
  * tell the driver which information elements are interesting in the sense
  * that we want to see changes in them. This will include
+ *
  *  - a list of information element IDs
  *  - a list of OUIs for the vendor information element
  *
index fc4f757107df0b51eae83781324337001ed7fb6d..0940598c002ff7fee832f9cf670b8006d0202ddc 100644 (file)
@@ -170,7 +170,7 @@ static inline struct net *copy_net_ns(unsigned long flags,
 extern struct list_head net_namespace_list;
 
 struct net *get_net_ns_by_pid(pid_t pid);
-struct net *get_net_ns_by_fd(int pid);
+struct net *get_net_ns_by_fd(int fd);
 
 #ifdef CONFIG_SYSCTL
 void ipx_register_sysctl(void);
index 50418052a520f396e8ae550160ca81e51ad89857..d9d52c020a709993fbbb02898ffe2931271a5ff7 100644 (file)
@@ -100,6 +100,9 @@ struct nf_conn {
 
        possible_net_t ct_net;
 
+#if IS_ENABLED(CONFIG_NF_NAT)
+       struct rhlist_head nat_bysource;
+#endif
        /* all members below initialized via memset */
        u8 __nfct_init_offset[0];
 
@@ -117,9 +120,6 @@ struct nf_conn {
        /* Extensions */
        struct nf_ct_ext *ext;
 
-#if IS_ENABLED(CONFIG_NF_NAT)
-       struct rhash_head       nat_bysource;
-#endif
        /* Storage reserved for other modules, must be the last member */
        union nf_conntrack_proto proto;
 };
index 498814626e28b7115345308694bb66d240933f9f..1723a67c0b0a887d689c58481189f77f723aa400 100644 (file)
@@ -30,8 +30,7 @@ static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
        if (net->ct.labels_used == 0)
                return NULL;
 
-       return nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS,
-                                   sizeof(struct nf_conn_labels), GFP_ATOMIC);
+       return nf_ct_ext_add(ct, NF_CT_EXT_LABELS, GFP_ATOMIC);
 #else
        return NULL;
 #endif
index 5031e072567bd85318d5a6ab240b3ab79199facd..b02af0bf577796687c457bb10def12d959019cb0 100644 (file)
@@ -145,7 +145,7 @@ static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
        return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE;
 }
 
-unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
+int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
 unsigned int nft_parse_register(const struct nlattr *attr);
 int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);
 
@@ -313,7 +313,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
  *     @size: maximum set size
  *     @nelems: number of elements
  *     @ndeact: number of deactivated elements queued for removal
- *     @timeout: default timeout value in msecs
+ *     @timeout: default timeout value in jiffies
  *     @gc_int: garbage collection interval in msecs
  *     @policy: set parameterization (see enum nft_set_policies)
  *     @udlen: user data length
@@ -542,7 +542,8 @@ void *nft_set_elem_init(const struct nft_set *set,
                        const struct nft_set_ext_tmpl *tmpl,
                        const u32 *key, const u32 *data,
                        u64 timeout, gfp_t gfp);
-void nft_set_elem_destroy(const struct nft_set *set, void *elem);
+void nft_set_elem_destroy(const struct nft_set *set, void *elem,
+                         bool destroy_expr);
 
 /**
  *     struct nft_set_gc_batch_head - nf_tables set garbage collection batch
@@ -693,7 +694,6 @@ static inline int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
 {
        int err;
 
-       __module_get(src->ops->type->owner);
        if (src->ops->clone) {
                dst->ops = src->ops;
                err = src->ops->clone(dst, src);
@@ -702,6 +702,8 @@ static inline int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
        } else {
                memcpy(dst, src, src->ops->size);
        }
+
+       __module_get(src->ops->type->owner);
        return 0;
 }
 
index 87a7f42e763963255afc32deaa774570bf03551a..31acc3f4f132d30d086208e510a0d54e745b29c2 100644 (file)
@@ -152,7 +152,7 @@ void sctp_unhash_endpoint(struct sctp_endpoint *);
 struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
                             struct sctphdr *, struct sctp_association **,
                             struct sctp_transport **);
-void sctp_err_finish(struct sock *, struct sctp_association *);
+void sctp_err_finish(struct sock *, struct sctp_transport *);
 void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
                           struct sctp_transport *t, __u32 pmtu);
 void sctp_icmp_redirect(struct sock *, struct sctp_transport *,
index ebf75db08e062dfe7867cc80c7699f593be16349..92b269709b9a8a7e5d69c55ac66b834501a2931c 100644 (file)
@@ -252,6 +252,7 @@ struct sock_common {
   *    @sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler)
   *    @sk_max_pacing_rate: Maximum pacing rate (%SO_MAX_PACING_RATE)
   *    @sk_sndbuf: size of send buffer in bytes
+  *    @sk_padding: unused element for alignment
   *    @sk_no_check_tx: %SO_NO_CHECK setting, set checksum in TX packets
   *    @sk_no_check_rx: allow zero checksum in RX packets
   *    @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
@@ -302,7 +303,8 @@ struct sock_common {
   *    @sk_backlog_rcv: callback to process the backlog
   *    @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0
   *    @sk_reuseport_cb: reuseport group container
- */
+  *    @sk_rcu: used during RCU grace period
+  */
 struct sock {
        /*
         * Now struct inet_timewait_sock also uses sock_common, so please just
@@ -1594,11 +1596,11 @@ static inline void sock_put(struct sock *sk)
 void sock_gen_put(struct sock *sk);
 
 int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested,
-                    unsigned int trim_cap);
+                    unsigned int trim_cap, bool refcounted);
 static inline int sk_receive_skb(struct sock *sk, struct sk_buff *skb,
                                 const int nested)
 {
-       return __sk_receive_skb(sk, skb, nested, 1);
+       return __sk_receive_skb(sk, skb, nested, 1, true);
 }
 
 static inline void sk_tx_queue_set(struct sock *sk, int tx_queue)
index f83b7f220a65ea7de2ff1083e0a6ef52e7619d6e..123979fe12bf780b50ed0967d8ba289c63f798a3 100644 (file)
@@ -794,12 +794,23 @@ struct tcp_skb_cb {
  */
 static inline int tcp_v6_iif(const struct sk_buff *skb)
 {
-       bool l3_slave = skb_l3mdev_slave(TCP_SKB_CB(skb)->header.h6.flags);
+       bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags);
 
        return l3_slave ? skb->skb_iif : TCP_SKB_CB(skb)->header.h6.iif;
 }
 #endif
 
+/* TCP_SKB_CB reference means this can not be used from early demux */
+static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
+       if (!net->ipv4.sysctl_tcp_l3mdev_accept &&
+           skb && ipv4_l3mdev_skb(TCP_SKB_CB(skb)->header.h4.flags))
+               return true;
+#endif
+       return false;
+}
+
 /* Due to TSO, an SKB can be composed of multiple actual
  * packets.  To keep these tracked properly, we use this.
  */
@@ -1209,6 +1220,7 @@ static inline void tcp_prequeue_init(struct tcp_sock *tp)
 
 bool tcp_prequeue(struct sock *sk, struct sk_buff *skb);
 bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb);
+int tcp_filter(struct sock *sk, struct sk_buff *skb);
 
 #undef STATE_TRACE
 
index ea53a87d880fad8e6621ed316281be5aa0726201..4948790d393d7617edba64603c60974942289ee4 100644 (file)
@@ -258,6 +258,7 @@ void udp_flush_pending_frames(struct sock *sk);
 void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst);
 int udp_rcv(struct sk_buff *skb);
 int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+int __udp_disconnect(struct sock *sk, int flags);
 int udp_disconnect(struct sock *sk, int flags);
 unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait);
 struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
index 0255613a54a4097392649f33e9ee2801ebe2570c..308adc4154f43e6233b901e0032c20932059bd64 100644 (file)
@@ -225,9 +225,9 @@ struct vxlan_config {
 struct vxlan_dev {
        struct hlist_node hlist;        /* vni hash table */
        struct list_head  next;         /* vxlan's per namespace list */
-       struct vxlan_sock *vn4_sock;    /* listening socket for IPv4 */
+       struct vxlan_sock __rcu *vn4_sock;      /* listening socket for IPv4 */
 #if IS_ENABLED(CONFIG_IPV6)
-       struct vxlan_sock *vn6_sock;    /* listening socket for IPv6 */
+       struct vxlan_sock __rcu *vn6_sock;      /* listening socket for IPv6 */
 #endif
        struct net_device *dev;
        struct net        *net;         /* netns for packet i/o */
diff --git a/include/sound/cs35l34.h b/include/sound/cs35l34.h
new file mode 100644 (file)
index 0000000..9c927cf
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * linux/sound/cs35l34.h -- Platform data for CS35l34
+ *
+ * Copyright (c) 2016 Cirrus Logic Inc.
+ *
+ * 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 __CS35L34_H
+#define __CS35L34_H
+
+struct cs35l34_platform_data {
+       /* Set AIF to half drive strength */
+       bool aif_half_drv;
+       /* Digital Soft Ramp Disable */
+       bool digsft_disable;
+       /* Amplifier Invert */
+       bool amp_inv;
+       /* Peak current (mA) */
+       unsigned int boost_peak;
+       /* Boost inductor value (nH) */
+       unsigned int boost_ind;
+       /* Boost Controller Voltage Setting (mV) */
+       unsigned int boost_vtge;
+       /* Gain Change Zero Cross */
+       bool gain_zc_disable;
+       /* SDIN Left/Right Selection */
+       unsigned int i2s_sdinloc;
+       /* TDM Rising Edge */
+       bool tdm_rising_edge;
+};
+
+#endif /* __CS35L34_H */
index 67be2445941a613bcc74918d8964bfe3aef907ff..1c8f9e1ef2a5a511a2df3bdbb8e8c6444b58f309 100644 (file)
@@ -71,7 +71,6 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
  * @slave_id: Slave requester id for the DMA channel.
  * @filter_data: Custom DMA channel filter data, this will usually be used when
  * requesting the DMA channel.
- * @chan_name: Custom channel name to use when requesting DMA channel.
  * @fifo_size: FIFO size of the DAI controller in bytes
  * @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now
  */
@@ -81,7 +80,6 @@ struct snd_dmaengine_dai_dma_data {
        u32 maxburst;
        unsigned int slave_id;
        void *filter_data;
-       const char *chan_name;
        unsigned int fifo_size;
        unsigned int flags;
 };
@@ -107,10 +105,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
  * playback.
  */
 #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3)
-/*
- * The PCM streams have custom channel names specified.
- */
-#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4)
 
 /**
  * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM
diff --git a/include/sound/rt5514.h b/include/sound/rt5514.h
new file mode 100644 (file)
index 0000000..ef18494
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * linux/sound/rt5514.h -- Platform data for RT5514
+ *
+ * Copyright 2016 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 __LINUX_SND_RT5514_H
+#define __LINUX_SND_RT5514_H
+
+struct rt5514_platform_data {
+       unsigned int dmic_init_delay;
+};
+
+#endif
+
diff --git a/include/sound/rt5665.h b/include/sound/rt5665.h
new file mode 100755 (executable)
index 0000000..963229e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * linux/sound/rt5665.h -- Platform data for RT5665
+ *
+ * Copyright 2016 Realtek Microelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_RT5665_H
+#define __LINUX_SND_RT5665_H
+
+enum rt5665_dmic1_data_pin {
+       RT5665_DMIC1_NULL,
+       RT5665_DMIC1_DATA_GPIO4,
+       RT5665_DMIC1_DATA_IN2N,
+};
+
+enum rt5665_dmic2_data_pin {
+       RT5665_DMIC2_NULL,
+       RT5665_DMIC2_DATA_GPIO5,
+       RT5665_DMIC2_DATA_IN2P,
+};
+
+enum rt5665_jd_src {
+       RT5665_JD_NULL,
+       RT5665_JD1,
+};
+
+struct rt5665_platform_data {
+       bool in1_diff;
+       bool in2_diff;
+       bool in3_diff;
+       bool in4_diff;
+
+       int ldo1_en; /* GPIO for LDO1_EN */
+
+       enum rt5665_dmic1_data_pin dmic1_data_pin;
+       enum rt5665_dmic2_data_pin dmic2_data_pin;
+       enum rt5665_jd_src jd_src;
+
+       unsigned int sar_hs_type;
+};
+
+#endif
+
index 964b7de1a1cc2ebd8cd58fe16487cc631caf9f71..b4082454b46f12d43d9a690614ec3a0e5d9e80e2 100644 (file)
@@ -207,6 +207,30 @@ struct snd_soc_dai_ops {
                struct snd_soc_dai *);
 };
 
+struct snd_soc_cdai_ops {
+       /*
+        * for compress ops
+        */
+       int (*startup)(struct snd_compr_stream *,
+                       struct snd_soc_dai *);
+       int (*shutdown)(struct snd_compr_stream *,
+                       struct snd_soc_dai *);
+       int (*set_params)(struct snd_compr_stream *,
+                       struct snd_compr_params *, struct snd_soc_dai *);
+       int (*get_params)(struct snd_compr_stream *,
+                       struct snd_codec *, struct snd_soc_dai *);
+       int (*set_metadata)(struct snd_compr_stream *,
+                       struct snd_compr_metadata *, struct snd_soc_dai *);
+       int (*get_metadata)(struct snd_compr_stream *,
+                       struct snd_compr_metadata *, struct snd_soc_dai *);
+       int (*trigger)(struct snd_compr_stream *, int,
+                       struct snd_soc_dai *);
+       int (*pointer)(struct snd_compr_stream *,
+                       struct snd_compr_tstamp *, struct snd_soc_dai *);
+       int (*ack)(struct snd_compr_stream *, size_t,
+                       struct snd_soc_dai *);
+};
+
 /*
  * Digital Audio Interface Driver.
  *
@@ -236,6 +260,7 @@ struct snd_soc_dai_driver {
 
        /* ops */
        const struct snd_soc_dai_ops *ops;
+       const struct snd_soc_cdai_ops *cops;
 
        /* DAI capabilities */
        struct snd_soc_pcm_stream capture;
@@ -268,8 +293,9 @@ struct snd_soc_dai {
        unsigned int symmetric_rates:1;
        unsigned int symmetric_channels:1;
        unsigned int symmetric_samplebits:1;
+       unsigned int probed:1;
+
        unsigned int active;
-       unsigned char probed:1;
 
        struct snd_soc_dapm_widget *playback_widget;
        struct snd_soc_dapm_widget *capture_widget;
index f60d755f7ac6c947ff5d6c817ae8ebce430f1224..a466f4bdc835948c21f27a5f9f57f91930db0090 100644 (file)
@@ -272,6 +272,16 @@ struct device;
 
 
 /* dapm kcontrol types */
+#define SOC_DAPM_DOUBLE(xname, reg, lshift, rshift, max, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value = SOC_DOUBLE_VALUE(reg, lshift, rshift, max, invert, 0) }
+#define SOC_DAPM_DOUBLE_R(xname, lreg, rreg, shift, max, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value = SOC_DOUBLE_R_VALUE(lreg, rreg, shift, max, invert) }
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
@@ -615,6 +625,10 @@ struct snd_soc_dapm_update {
        int reg;
        int mask;
        int val;
+       int reg2;
+       int mask2;
+       int val2;
+       bool has_second_set;
 };
 
 struct snd_soc_dapm_wcache {
index 4f1c784e44f634016153b3ff4f0a1b7d3b652b95..42339c0f3532800be447e41e24f4aed089972f4d 100644 (file)
@@ -782,6 +782,8 @@ struct snd_soc_component_driver {
 
        int (*probe)(struct snd_soc_component *);
        void (*remove)(struct snd_soc_component *);
+       int (*suspend)(struct snd_soc_component *);
+       int (*resume)(struct snd_soc_component *);
 
        /* DT */
        int (*of_xlate_dai_name)(struct snd_soc_component *component,
@@ -807,9 +809,11 @@ struct snd_soc_component {
 
        unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
        unsigned int registered_as_component:1;
+       unsigned int auxiliary:1; /* for auxiliary component of the card */
+       unsigned int suspended:1; /* is in suspend PM state */
 
        struct list_head list;
-       struct list_head list_aux; /* for auxiliary component of the card */
+       struct list_head card_list;
 
        struct snd_soc_dai_driver *dai_drv;
        int num_dai;
@@ -852,6 +856,8 @@ struct snd_soc_component {
 
        int (*probe)(struct snd_soc_component *);
        void (*remove)(struct snd_soc_component *);
+       int (*suspend)(struct snd_soc_component *);
+       int (*resume)(struct snd_soc_component *);
 
        /* machine specific init */
        int (*init)(struct snd_soc_component *component);
@@ -868,11 +874,9 @@ struct snd_soc_codec {
        const struct snd_soc_codec_driver *driver;
 
        struct list_head list;
-       struct list_head card_list;
 
        /* runtime */
        unsigned int cache_bypass:1; /* Suppress access to the cache */
-       unsigned int suspended:1; /* Codec is in suspend PM state */
        unsigned int cache_init:1; /* codec cache has been initialized */
 
        /* codec IO */
@@ -1025,13 +1029,13 @@ struct snd_soc_dai_link {
        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;
 
+       /* For unidirectional dai links */
+       unsigned int playback_only:1;
+       unsigned int capture_only:1;
+
        /* Keep DAI active over suspend */
        unsigned int ignore_suspend:1;
 
@@ -1148,7 +1152,6 @@ struct snd_soc_card {
         */
        struct snd_soc_aux_dev *aux_dev;
        int num_aux_devs;
-       struct list_head aux_comp_list;
 
        const struct snd_kcontrol_new *controls;
        int num_controls;
@@ -1170,7 +1173,7 @@ struct snd_soc_card {
        struct work_struct deferred_resume_work;
 
        /* lists of probed devices belonging to this card */
-       struct list_head codec_dev_list;
+       struct list_head component_dev_list;
 
        struct list_head widgets;
        struct list_head paths;
@@ -1203,14 +1206,11 @@ struct snd_soc_pcm_runtime {
        enum snd_soc_pcm_subclass pcm_subclass;
        struct snd_pcm_ops ops;
 
-       unsigned int dev_registered:1;
-
        /* Dynamic PCM BE runtime data */
        struct snd_soc_dpcm_runtime dpcm[2];
        int fe_compr;
 
        long pmdown_time;
-       unsigned char pop_wait:1;
 
        /* runtime devices */
        struct snd_pcm *pcm;
@@ -1219,7 +1219,6 @@ struct snd_soc_pcm_runtime {
        struct snd_soc_platform *platform;
        struct snd_soc_dai *codec_dai;
        struct snd_soc_dai *cpu_dai;
-       struct snd_soc_component *component; /* Only valid for AUX dev rtds */
 
        struct snd_soc_dai **codec_dais;
        unsigned int num_codecs;
@@ -1232,6 +1231,10 @@ struct snd_soc_pcm_runtime {
 
        unsigned int num; /* 0-based and monotonic increasing */
        struct list_head list; /* rtd list of the soc card */
+
+       /* bit field */
+       unsigned int dev_registered:1;
+       unsigned int pop_wait:1;
 };
 
 /* mixer control */
@@ -1541,11 +1544,10 @@ static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platfo
 
 static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
 {
-       INIT_LIST_HEAD(&card->codec_dev_list);
        INIT_LIST_HEAD(&card->widgets);
        INIT_LIST_HEAD(&card->paths);
        INIT_LIST_HEAD(&card->dapm_list);
-       INIT_LIST_HEAD(&card->aux_comp_list);
+       INIT_LIST_HEAD(&card->component_dev_list);
 }
 
 static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
@@ -1642,25 +1644,43 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform(
 int snd_soc_util_init(void);
 void snd_soc_util_exit(void);
 
-int snd_soc_of_parse_card_name(struct snd_soc_card *card,
-                              const char *propname);
-int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
-                                         const char *propname);
+#define snd_soc_of_parse_card_name(card, propname) \
+       snd_soc_of_parse_card_name_from_node(card, NULL, propname)
+int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
+                                        struct device_node *np,
+                                        const char *propname);
+#define snd_soc_of_parse_audio_simple_widgets(card, propname)\
+       snd_soc_of_parse_audio_simple_widgets_from_node(card, NULL, propname)
+int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card,
+                                                   struct device_node *np,
+                                                   const char *propname);
+
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
                              unsigned int *tx_mask,
                              unsigned int *rx_mask,
                              unsigned int *slots,
                              unsigned int *slot_width);
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+#define snd_soc_of_parse_audio_prefix(card, codec_conf, of_node, propname) \
+       snd_soc_of_parse_audio_prefix_from_node(card, NULL, codec_conf, \
+                                               of_node, propname)
+void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card,
+                                  struct device_node *np,
                                   struct snd_soc_codec_conf *codec_conf,
                                   struct device_node *of_node,
                                   const char *propname);
-int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
-                                  const char *propname);
+
+#define snd_soc_of_parse_audio_routing(card, propname) \
+       snd_soc_of_parse_audio_routing_from_node(card, NULL, propname)
+int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card,
+                                            struct device_node *np,
+                                            const char *propname);
+
 unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
                                     const char *prefix,
                                     struct device_node **bitclkmaster,
                                     struct device_node **framemaster);
+int snd_soc_get_dai_name(struct of_phandle_args *args,
+                        const char **dai_name);
 int snd_soc_of_get_dai_name(struct device_node *of_node,
                            const char **dai_name);
 int snd_soc_of_get_dai_link_codecs(struct device *dev,
@@ -1697,4 +1717,24 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
        mutex_unlock(&dapm->card->dapm_mutex);
 }
 
+int snd_soc_component_enable_pin(struct snd_soc_component *component,
+                                const char *pin);
+int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component,
+                                         const char *pin);
+int snd_soc_component_disable_pin(struct snd_soc_component *component,
+                                 const char *pin);
+int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component,
+                                          const char *pin);
+int snd_soc_component_nc_pin(struct snd_soc_component *component,
+                            const char *pin);
+int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component,
+                                     const char *pin);
+int snd_soc_component_get_pin_status(struct snd_soc_component *component,
+                                    const char *pin);
+int snd_soc_component_force_enable_pin(struct snd_soc_component *component,
+                                      const char *pin);
+int snd_soc_component_force_enable_pin_unlocked(
+                                       struct snd_soc_component *component,
+                                       const char *pin);
+
 #endif
index fb8e3b6febdff7f5fdb3f0335455b9e074647c40..c2119008990a36a54b43ee66d57024df6330e893 100644 (file)
@@ -177,6 +177,7 @@ enum tcm_sense_reason_table {
        TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED    = R(0x15),
        TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED  = R(0x16),
        TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED  = R(0x17),
+       TCM_COPY_TARGET_DEVICE_NOT_REACHABLE    = R(0x18),
 #undef R
 };
 
index dbfee7e86ba6429319188a03d618881ae34a9ef0..9b1462e38b821a762b284b44a20a96de9f0930d9 100644 (file)
@@ -730,10 +730,6 @@ __SYSCALL(__NR_pkey_mprotect, sys_pkey_mprotect)
 __SYSCALL(__NR_pkey_alloc,    sys_pkey_alloc)
 #define __NR_pkey_free 290
 __SYSCALL(__NR_pkey_free,     sys_pkey_free)
-#define __NR_pkey_get 291
-//__SYSCALL(__NR_pkey_get,      sys_pkey_get)
-#define __NR_pkey_set 292
-//__SYSCALL(__NR_pkey_set,      sys_pkey_set)
 
 #undef __NR_syscalls
 #define __NR_syscalls 291
index 6965d0909554573d723d9d7eca3bb205e12d2760..cd2be1c8e9fb6cfac94b6dc9e734274a7c1f9932 100644 (file)
@@ -75,6 +75,7 @@ header-y += bpf_perf_event.h
 header-y += bpf.h
 header-y += bpqether.h
 header-y += bsg.h
+header-y += bt-bmc.h
 header-y += btrfs.h
 header-y += can.h
 header-y += capability.h
index 5cd4d4d2dd1d226ba6e5b024a697e71dfde9ac7d..9c9c6ad55f1487b9b4cead653fc996930603b259 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/atmapi.h>
 #include <linux/atmioc.h>
-#include <linux/time.h>
 
 #define ZATM_GETPOOL   _IOW('a',ATMIOC_SARPRV+1,struct atmif_sioc)
                                                /* get pool statistics */
index a6c35e1a89ad9297b69c048200328b8ec6490fa1..05865edaefdae02a0f997eb3bdcc82fd921fb9db 100644 (file)
@@ -5,9 +5,7 @@
  *     Defines for the BPQETHER pseudo device driver
  */
 
-#ifndef __LINUX_IF_ETHER_H
 #include <linux/if_ether.h>
-#endif
 
 #define SIOCSBPQETHOPT         (SIOCDEVPRIVATE+0)      /* reserved */
 #define SIOCSBPQETHADDR                (SIOCDEVPRIVATE+1)
diff --git a/include/uapi/linux/bt-bmc.h b/include/uapi/linux/bt-bmc.h
new file mode 100644 (file)
index 0000000..d9ec766
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015-2016, IBM Corporation.
+ *
+ * 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 _UAPI_LINUX_BT_BMC_H
+#define _UAPI_LINUX_BT_BMC_H
+
+#include <linux/ioctl.h>
+
+#define __BT_BMC_IOCTL_MAGIC   0xb1
+#define BT_BMC_IOCTL_SMS_ATN   _IO(__BT_BMC_IOCTL_MAGIC, 0x00)
+
+#endif /* _UAPI_LINUX_BT_BMC_H */
index 9692cda5f8fc2fe7789de59f93281cf4c0bd2a5e..c48d93a28d1acbb905b5d62cb2e8436c20ec8c7e 100644 (file)
@@ -196,5 +196,6 @@ struct can_filter {
 };
 
 #define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */
 
 #endif /* !_UAPI_CAN_H */
index 099a4200732cc187f069331cbf3cbfa35e9a7e52..8e547231c1b74bd21ba194127de3b6357cba84b9 100644 (file)
@@ -119,8 +119,7 @@ struct ethtool_cmd {
 static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
                                         __u32 speed)
 {
-
-       ep->speed = (__u16)speed;
+       ep->speed = (__u16)(speed & 0xFFFF);
        ep->speed_hi = (__u16)(speed >> 16);
 }
 
index e601c8c3bdc777b6458fe99d39de1f91b16f66d9..1158a043342ac6a77edcd3a4180632b4ef4c87e0 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/hdlc/ioctl.h>
 
 /* For glibc compatibility. An empty enum does not compile. */
-#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && \
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || \
     __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0
 /**
  * enum net_device_flags - &struct net_device flags
@@ -99,7 +99,7 @@ enum net_device_flags {
        IFF_ECHO                        = 1<<18, /* volatile */
 #endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
 };
-#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */
 
 /* for compatibility with glibc net/if.h */
 #if __UAPI_DEF_IF_NET_DEVICE_FLAGS
index d6d071fc3c568249bf70f24602f95770eb1643df..3af60ee69053322b9c6ca72d3120ce9f23da1c80 100644 (file)
  * Control a data application associated with the currently viewed channel,
  * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
  */
-#define KEY_DATA                       0x275
+#define KEY_DATA                       0x277
 
 #define BTN_TRIGGER_HAPPY              0x2c0
 #define BTN_TRIGGER_HAPPY1             0x2c0
index 300ef255d1e0ec496356fcbf7152a7c674590a44..4ee67cb99143deefbe11abafdd5bb49d18dba5ba 100644 (file)
@@ -972,12 +972,19 @@ struct kvm_irqfd {
        __u8  pad[16];
 };
 
+/* For KVM_CAP_ADJUST_CLOCK */
+
+/* Do not use 1, KVM_CHECK_EXTENSION returned it before we had flags.  */
+#define KVM_CLOCK_TSC_STABLE           2
+
 struct kvm_clock_data {
        __u64 clock;
        __u32 flags;
        __u32 pad[9];
 };
 
+/* For KVM_CAP_SW_TLB */
+
 #define KVM_MMU_FSL_BOOKE_NOHV         0
 #define KVM_MMU_FSL_BOOKE_HV           1
 
index cd26d7a0fd07094499f97568dc8ca4f50ae93c0f..03f194aeadc51b56d468236c9bba67afbe0b86bd 100644 (file)
@@ -5,6 +5,7 @@ header-y += nf_conntrack_ftp.h
 header-y += nf_conntrack_sctp.h
 header-y += nf_conntrack_tcp.h
 header-y += nf_conntrack_tuple_common.h
+header-y += nf_log.h
 header-y += nf_tables.h
 header-y += nf_tables_compat.h
 header-y += nf_nat.h
index 262f0379d83ac1965d8f792b5f1d3b8634f86d69..5a78be51810123a000bfad4d62a5e6e58c987a2d 100644 (file)
@@ -350,7 +350,7 @@ struct rtnexthop {
 #define RTNH_F_OFFLOAD         8       /* offloaded route */
 #define RTNH_F_LINKDOWN                16      /* carrier-down on nexthop */
 
-#define RTNH_COMPARE_MASK      (RTNH_F_DEAD | RTNH_F_LINKDOWN)
+#define RTNH_COMPARE_MASK      (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD)
 
 /* Macros to handle hexthops */
 
index e3969bd939e41d7fb1ff47f61344fad5f1cae482..e3db7403296fdf8a7f72ec44523acea9ba8b0b9b 100644 (file)
@@ -11,3 +11,5 @@ header-y += tc_vlan.h
 header-y += tc_bpf.h
 header-y += tc_connmark.h
 header-y += tc_ife.h
+header-y += tc_tunnel_key.h
+header-y += tc_skbmod.h
index 33d00a4ce6567f03f1cb52b08a5e72bda04efbaf..819d895edfdca7f9b146f187b0636410eb5bde7f 100644 (file)
 #include <linux/types.h>
 #include <sound/asound.h>
 
-#ifndef __KERNEL__
-#error This API is an early revision and not enabled in the current
-#error kernel release, it will be enabled in a future kernel version
-#error with incompatible changes to what is here.
-#endif
-
 /*
  * Maximum number of channels topology kcontrol can represent.
  */
index 1ee2e943d66a319c6d0536b9deb96b3ea95c5be9..93392bedcc5870d64514ae84ab00095de4b9971f 100644 (file)
  *
  * %SKL_TKN_STR_LIB_NAME:       Specifies the library name
  *
+ * %SKL_TKN_U32_PMODE:         Specifies the power mode for pipe
+ *
+ * %SKL_TKL_U32_D0I3_CAPS:     Specifies the D0i3 capability for module
+ *
  * module_id and loadable flags dont have tokens as these values will be
  * read from the DSP FW manifest
  */
@@ -208,7 +212,9 @@ enum SKL_TKNS {
        SKL_TKN_U32_PROC_DOMAIN,
        SKL_TKN_U32_LIB_COUNT,
        SKL_TKN_STR_LIB_NAME,
-       SKL_TKN_MAX = SKL_TKN_STR_LIB_NAME,
+       SKL_TKN_U32_PMODE,
+       SKL_TKL_U32_D0I3_CAPS,
+       SKL_TKN_MAX = SKL_TKL_U32_D0I3_CAPS,
 };
 
 #endif
index 8a09b32e07d6c33351993c4c6beb19f5782d6c94..dd4104c9aa12c6a517ff7066d52ab6057d26e586 100644 (file)
@@ -272,7 +272,7 @@ int __init rd_load_image(char *from)
                sys_write(out_fd, buf, BLOCK_SIZE);
 #if !defined(CONFIG_S390)
                if (!(i % 16)) {
-                       printk("%c\b", rotator[rotate & 0x3]);
+                       pr_cont("%c\b", rotator[rotate & 0x3]);
                        rotate++;
                }
 #endif
index a521999de4f103954e40db932e8903f3ed7e48f1..bf74eaa5c39f208ea5f1ee41db38e57349512e7d 100644 (file)
@@ -53,7 +53,7 @@ static struct msg_msg *alloc_msg(size_t len)
        size_t alen;
 
        alen = min(len, DATALEN_MSG);
-       msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
+       msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT);
        if (msg == NULL)
                return NULL;
 
@@ -65,7 +65,7 @@ static struct msg_msg *alloc_msg(size_t len)
        while (len > 0) {
                struct msg_msgseg *seg;
                alen = min(len, DATALEN_SEG);
-               seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
+               seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);
                if (seg == NULL)
                        goto out_err;
                *pseg = seg;
index 570eeca7bdfa79ce16d18ee94fac64c40aa11d38..ad1bc67aff1b514fe9801e695ef9f428091227fc 100644 (file)
@@ -687,7 +687,8 @@ static void delete_all_elements(struct bpf_htab *htab)
 
                hlist_for_each_entry_safe(l, n, head, hash_node) {
                        hlist_del_rcu(&l->hash_node);
-                       htab_elem_free(htab, l);
+                       if (l->state != HTAB_EXTRA_ELEM_USED)
+                               htab_elem_free(htab, l);
                }
        }
 }
index 228f962447a508f50ec2a2f81f83bdb1f9368e77..237f3d6a7ddc7ad7db83dbec73c27c8ca67dc0ea 100644 (file)
@@ -194,7 +194,7 @@ static int map_create(union bpf_attr *attr)
 
        err = bpf_map_charge_memlock(map);
        if (err)
-               goto free_map;
+               goto free_map_nouncharge;
 
        err = bpf_map_new_fd(map);
        if (err < 0)
@@ -204,6 +204,8 @@ static int map_create(union bpf_attr *attr)
        return err;
 
 free_map:
+       bpf_map_uncharge_memlock(map);
+free_map_nouncharge:
        map->ops->map_free(map);
        return err;
 }
index 99a7e5b388f236ea62f23afefac5c252416d2b60..8199821f54cf2c676204abb7b4cc9fad88524b4a 100644 (file)
@@ -216,8 +216,8 @@ static void print_verifier_state(struct bpf_verifier_state *state)
                                reg->map_ptr->key_size,
                                reg->map_ptr->value_size);
                if (reg->min_value != BPF_REGISTER_MIN_RANGE)
-                       verbose(",min_value=%llu",
-                               (unsigned long long)reg->min_value);
+                       verbose(",min_value=%lld",
+                               (long long)reg->min_value);
                if (reg->max_value != BPF_REGISTER_MAX_RANGE)
                        verbose(",max_value=%llu",
                                (unsigned long long)reg->max_value);
@@ -758,7 +758,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off,
                         * index'es we need to make sure that whatever we use
                         * will have a set floor within our range.
                         */
-                       if ((s64)reg->min_value < 0) {
+                       if (reg->min_value < 0) {
                                verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
                                        regno);
                                return -EACCES;
@@ -1468,7 +1468,8 @@ static void check_reg_overflow(struct bpf_reg_state *reg)
 {
        if (reg->max_value > BPF_REGISTER_MAX_RANGE)
                reg->max_value = BPF_REGISTER_MAX_RANGE;
-       if ((s64)reg->min_value < BPF_REGISTER_MIN_RANGE)
+       if (reg->min_value < BPF_REGISTER_MIN_RANGE ||
+           reg->min_value > BPF_REGISTER_MAX_RANGE)
                reg->min_value = BPF_REGISTER_MIN_RANGE;
 }
 
@@ -1476,7 +1477,8 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
                                    struct bpf_insn *insn)
 {
        struct bpf_reg_state *regs = env->cur_state.regs, *dst_reg;
-       u64 min_val = BPF_REGISTER_MIN_RANGE, max_val = BPF_REGISTER_MAX_RANGE;
+       s64 min_val = BPF_REGISTER_MIN_RANGE;
+       u64 max_val = BPF_REGISTER_MAX_RANGE;
        bool min_set = false, max_set = false;
        u8 opcode = BPF_OP(insn->code);
 
@@ -1512,22 +1514,43 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
                return;
        }
 
+       /* If one of our values was at the end of our ranges then we can't just
+        * do our normal operations to the register, we need to set the values
+        * to the min/max since they are undefined.
+        */
+       if (min_val == BPF_REGISTER_MIN_RANGE)
+               dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
+       if (max_val == BPF_REGISTER_MAX_RANGE)
+               dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
+
        switch (opcode) {
        case BPF_ADD:
-               dst_reg->min_value += min_val;
-               dst_reg->max_value += max_val;
+               if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+                       dst_reg->min_value += min_val;
+               if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+                       dst_reg->max_value += max_val;
                break;
        case BPF_SUB:
-               dst_reg->min_value -= min_val;
-               dst_reg->max_value -= max_val;
+               if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+                       dst_reg->min_value -= min_val;
+               if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+                       dst_reg->max_value -= max_val;
                break;
        case BPF_MUL:
-               dst_reg->min_value *= min_val;
-               dst_reg->max_value *= max_val;
+               if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+                       dst_reg->min_value *= min_val;
+               if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+                       dst_reg->max_value *= max_val;
                break;
        case BPF_AND:
-               /* & is special since it could end up with 0 bits set. */
-               dst_reg->min_value &= min_val;
+               /* Disallow AND'ing of negative numbers, ain't nobody got time
+                * for that.  Otherwise the minimum is 0 and the max is the max
+                * value we could AND against.
+                */
+               if (min_val < 0)
+                       dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
+               else
+                       dst_reg->min_value = 0;
                dst_reg->max_value = max_val;
                break;
        case BPF_LSH:
@@ -1537,24 +1560,25 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
                 */
                if (min_val > ilog2(BPF_REGISTER_MAX_RANGE))
                        dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
-               else
+               else if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
                        dst_reg->min_value <<= min_val;
 
                if (max_val > ilog2(BPF_REGISTER_MAX_RANGE))
                        dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
-               else
+               else if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
                        dst_reg->max_value <<= max_val;
                break;
        case BPF_RSH:
-               dst_reg->min_value >>= min_val;
-               dst_reg->max_value >>= max_val;
-               break;
-       case BPF_MOD:
-               /* % is special since it is an unsigned modulus, so the floor
-                * will always be 0.
+               /* RSH by a negative number is undefined, and the BPF_RSH is an
+                * unsigned shift, so make the appropriate casts.
                 */
-               dst_reg->min_value = 0;
-               dst_reg->max_value = max_val - 1;
+               if (min_val < 0 || dst_reg->min_value < 0)
+                       dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
+               else
+                       dst_reg->min_value =
+                               (u64)(dst_reg->min_value) >> min_val;
+               if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
+                       dst_reg->max_value >>= max_val;
                break;
        default:
                reset_reg_range_values(regs, insn->dst_reg);
@@ -2430,6 +2454,7 @@ static bool states_equal(struct bpf_verifier_env *env,
                         struct bpf_verifier_state *old,
                         struct bpf_verifier_state *cur)
 {
+       bool varlen_map_access = env->varlen_map_value_access;
        struct bpf_reg_state *rold, *rcur;
        int i;
 
@@ -2443,12 +2468,17 @@ static bool states_equal(struct bpf_verifier_env *env,
                /* If the ranges were not the same, but everything else was and
                 * we didn't do a variable access into a map then we are a-ok.
                 */
-               if (!env->varlen_map_value_access &&
+               if (!varlen_map_access &&
                    rold->type == rcur->type && rold->imm == rcur->imm)
                        continue;
 
+               /* If we didn't map access then again we don't care about the
+                * mismatched range values and it's ok if our old type was
+                * UNKNOWN and we didn't go to a NOT_INIT'ed reg.
+                */
                if (rold->type == NOT_INIT ||
-                   (rold->type == UNKNOWN_VALUE && rcur->type != NOT_INIT))
+                   (!varlen_map_access && rold->type == UNKNOWN_VALUE &&
+                    rcur->type != NOT_INIT))
                        continue;
 
                if (rold->type == PTR_TO_PACKET && rcur->type == PTR_TO_PACKET &&
index 5df20d6d152071b40244fb5d85279b8040a641ba..29de1a9352c005c0d4808d2f842c15d29df1b2f8 100644 (file)
@@ -228,7 +228,7 @@ static struct {
        .wq = __WAIT_QUEUE_HEAD_INITIALIZER(cpu_hotplug.wq),
        .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock),
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-       .dep_map = {.name = "cpu_hotplug.lock" },
+       .dep_map = STATIC_LOCKDEP_MAP_INIT("cpu_hotplug.dep_map", &cpu_hotplug.dep_map),
 #endif
 };
 
index c6e47e97b33fdb7b0bbabf91016d51bc76d4b63c..02c8421f8c0190135995a31731d6e61c3064a9e8 100644 (file)
@@ -902,7 +902,15 @@ list_update_cgroup_event(struct perf_event *event,
         * this will always be called from the right CPU.
         */
        cpuctx = __get_cpu_context(ctx);
-       cpuctx->cgrp = add ? event->cgrp : NULL;
+
+       /*
+        * cpuctx->cgrp is NULL until a cgroup event is sched in or
+        * ctx->nr_cgroup == 0 .
+        */
+       if (add && perf_cgroup_from_task(current, ctx) == event->cgrp)
+               cpuctx->cgrp = event->cgrp;
+       else if (!add)
+               cpuctx->cgrp = NULL;
 }
 
 #else /* !CONFIG_CGROUP_PERF */
@@ -1960,6 +1968,12 @@ void perf_event_disable(struct perf_event *event)
 }
 EXPORT_SYMBOL_GPL(perf_event_disable);
 
+void perf_event_disable_inatomic(struct perf_event *event)
+{
+       event->pending_disable = 1;
+       irq_work_queue(&event->pending);
+}
+
 static void perf_set_shadow_time(struct perf_event *event,
                                 struct perf_event_context *ctx,
                                 u64 tstamp)
@@ -7075,8 +7089,8 @@ static int __perf_event_overflow(struct perf_event *event,
        if (events && atomic_dec_and_test(&event->event_limit)) {
                ret = 1;
                event->pending_kill = POLL_HUP;
-               event->pending_disable = 1;
-               irq_work_queue(&event->pending);
+
+               perf_event_disable_inatomic(event);
        }
 
        READ_ONCE(event->overflow_handler)(event, data, regs);
@@ -8012,6 +8026,7 @@ restart:
  * if <size> is not specified, the range is treated as a single address.
  */
 enum {
+       IF_ACT_NONE = -1,
        IF_ACT_FILTER,
        IF_ACT_START,
        IF_ACT_STOP,
@@ -8035,6 +8050,7 @@ static const match_table_t if_tokens = {
        { IF_SRC_KERNEL,        "%u/%u" },
        { IF_SRC_FILEADDR,      "%u@%s" },
        { IF_SRC_KERNELADDR,    "%u" },
+       { IF_ACT_NONE,          NULL },
 };
 
 /*
@@ -8855,7 +8871,10 @@ EXPORT_SYMBOL_GPL(perf_pmu_register);
 
 void perf_pmu_unregister(struct pmu *pmu)
 {
+       int remove_device;
+
        mutex_lock(&pmus_lock);
+       remove_device = pmu_bus_running;
        list_del_rcu(&pmu->entry);
        mutex_unlock(&pmus_lock);
 
@@ -8869,10 +8888,12 @@ void perf_pmu_unregister(struct pmu *pmu)
        free_percpu(pmu->pmu_disable_count);
        if (pmu->type >= PERF_TYPE_MAX)
                idr_remove(&pmu_idr, pmu->type);
-       if (pmu->nr_addr_filters)
-               device_remove_file(pmu->dev, &dev_attr_nr_addr_filters);
-       device_del(pmu->dev);
-       put_device(pmu->dev);
+       if (remove_device) {
+               if (pmu->nr_addr_filters)
+                       device_remove_file(pmu->dev, &dev_attr_nr_addr_filters);
+               device_del(pmu->dev);
+               put_device(pmu->dev);
+       }
        free_pmu_context(pmu);
 }
 EXPORT_SYMBOL_GPL(perf_pmu_unregister);
index d4129bb05e5d044101ba2cbea672f96954b69a51..f9ec9add21647fb4b60c3be08f515112b4bf4a25 100644 (file)
@@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
 
 retry:
        /* Read the page with vaddr into memory */
-       ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
+       ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
+                       &vma);
        if (ret <= 0)
                return ret;
 
@@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
         * but we treat this as a 'remote' access since it is
         * essentially a kernel access to the memory.
         */
-       result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
+       result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
+                       NULL);
        if (result < 0)
                return result;
 
index 9d68c45ebbe30e34290dfda571f7d75e01ce3d97..3076f3089919b60697f296ec01126e0af5947bcc 100644 (file)
@@ -836,6 +836,7 @@ void __noreturn do_exit(long code)
         */
        perf_event_exit_task(tsk);
 
+       sched_autogroup_exit_task(tsk);
        cgroup_exit(tsk);
 
        /*
index 623259fc794d034f7b4ab9144e2a61a7233381b6..997ac1d584f76b0e42551975bdae960e61c0807e 100644 (file)
@@ -315,6 +315,9 @@ static void account_kernel_stack(struct task_struct *tsk, int account)
 
 static void release_task_stack(struct task_struct *tsk)
 {
+       if (WARN_ON(tsk->state != TASK_DEAD))
+               return;  /* Better to leak the stack than to free prematurely */
+
        account_kernel_stack(tsk, -1);
        arch_release_thread_stack(tsk->stack);
        free_thread_stack(tsk);
@@ -1862,6 +1865,7 @@ bad_fork_cleanup_count:
        atomic_dec(&p->cred->user->processes);
        exit_creds(p);
 bad_fork_free:
+       p->state = TASK_DEAD;
        put_task_stack(p);
        free_task(p);
 fork_out:
index 0c5f1a5db654c7da7db4ec168ef44516407d6af5..6b669593e7eb18b18743a771415976a8c17b6920 100644 (file)
@@ -721,6 +721,7 @@ int irq_set_parent(int irq, int parent_irq)
        irq_put_desc_unlock(desc, flags);
        return 0;
 }
+EXPORT_SYMBOL_GPL(irq_set_parent);
 #endif
 
 /*
@@ -1340,12 +1341,12 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
        } else if (new->flags & IRQF_TRIGGER_MASK) {
                unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;
-               unsigned int omsk = irq_settings_get_trigger_mask(desc);
+               unsigned int omsk = irqd_get_trigger_type(&desc->irq_data);
 
                if (nmsk != omsk)
                        /* hope the handler works with current  trigger mode */
                        pr_warn("irq %d uses trigger mode %u; requested %u\n",
-                               irq, nmsk, omsk);
+                               irq, omsk, nmsk);
        }
 
        *old_ptr = new;
index 8d44b3fea9d08f901e3b24ed4a619a4883d4042f..3cbb0c879705f7a29f1d5bfad58551c098e69432 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/printk.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/vmalloc.h>
@@ -53,8 +54,15 @@ void notrace __sanitizer_cov_trace_pc(void)
        /*
         * We are interested in code coverage as a function of a syscall inputs,
         * so we ignore code executed in interrupts.
+        * The checks for whether we are in an interrupt are open-coded, because
+        * 1. We can't use in_interrupt() here, since it also returns true
+        *    when we are inside local_bh_disable() section.
+        * 2. We don't want to use (in_irq() | in_serving_softirq() | in_nmi()),
+        *    since that leads to slower generated code (three separate tests,
+        *    one for each of the flags).
         */
-       if (!t || in_interrupt())
+       if (!t || (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_OFFSET
+                                                       | NMI_MASK)))
                return;
        mode = READ_ONCE(t->kcov_mode);
        if (mode == KCOV_MODE_TRACE) {
index 589d763a49b3952322f08c00286675f314a3f76c..4d7ffc0a0d0069af114da7c795967d695a135e14 100644 (file)
@@ -506,13 +506,13 @@ static void __print_lock_name(struct lock_class *class)
        name = class->name;
        if (!name) {
                name = __get_key_name(class->key, str);
-               printk("%s", name);
+               printk(KERN_CONT "%s", name);
        } else {
-               printk("%s", name);
+               printk(KERN_CONT "%s", name);
                if (class->name_version > 1)
-                       printk("#%d", class->name_version);
+                       printk(KERN_CONT "#%d", class->name_version);
                if (class->subclass)
-                       printk("/%d", class->subclass);
+                       printk(KERN_CONT "/%d", class->subclass);
        }
 }
 
@@ -522,9 +522,9 @@ static void print_lock_name(struct lock_class *class)
 
        get_usage_chars(class, usage);
 
-       printk(" (");
+       printk(KERN_CONT " (");
        __print_lock_name(class);
-       printk("){%s}", usage);
+       printk(KERN_CONT "){%s}", usage);
 }
 
 static void print_lockdep_cache(struct lockdep_map *lock)
@@ -536,7 +536,7 @@ static void print_lockdep_cache(struct lockdep_map *lock)
        if (!name)
                name = __get_key_name(lock->key->subkeys, str);
 
-       printk("%s", name);
+       printk(KERN_CONT "%s", name);
 }
 
 static void print_lock(struct held_lock *hlock)
@@ -551,13 +551,13 @@ static void print_lock(struct held_lock *hlock)
        barrier();
 
        if (!class_idx || (class_idx - 1) >= MAX_LOCKDEP_KEYS) {
-               printk("<RELEASED>\n");
+               printk(KERN_CONT "<RELEASED>\n");
                return;
        }
 
        print_lock_name(lock_classes + class_idx - 1);
-       printk(", at: ");
-       print_ip_sym(hlock->acquire_ip);
+       printk(KERN_CONT ", at: [<%p>] %pS\n",
+               (void *)hlock->acquire_ip, (void *)hlock->acquire_ip);
 }
 
 static void lockdep_print_held_locks(struct task_struct *curr)
@@ -792,8 +792,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
 
                printk("\nnew class %p: %s", class->key, class->name);
                if (class->name_version > 1)
-                       printk("#%d", class->name_version);
-               printk("\n");
+                       printk(KERN_CONT "#%d", class->name_version);
+               printk(KERN_CONT "\n");
                dump_stack();
 
                if (!graph_lock()) {
@@ -1071,7 +1071,7 @@ print_circular_bug_entry(struct lock_list *target, int depth)
                return 0;
        printk("\n-> #%u", depth);
        print_lock_name(target->class);
-       printk(":\n");
+       printk(KERN_CONT ":\n");
        print_stack_trace(&target->trace, 6);
 
        return 0;
@@ -1102,11 +1102,11 @@ print_circular_lock_scenario(struct held_lock *src,
        if (parent != source) {
                printk("Chain exists of:\n  ");
                __print_lock_name(source);
-               printk(" --> ");
+               printk(KERN_CONT " --> ");
                __print_lock_name(parent);
-               printk(" --> ");
+               printk(KERN_CONT " --> ");
                __print_lock_name(target);
-               printk("\n\n");
+               printk(KERN_CONT "\n\n");
        }
 
        printk(" Possible unsafe locking scenario:\n\n");
@@ -1114,16 +1114,16 @@ print_circular_lock_scenario(struct held_lock *src,
        printk("       ----                    ----\n");
        printk("  lock(");
        __print_lock_name(target);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("                               lock(");
        __print_lock_name(parent);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("                               lock(");
        __print_lock_name(target);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("  lock(");
        __print_lock_name(source);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("\n *** DEADLOCK ***\n\n");
 }
 
@@ -1359,22 +1359,22 @@ static void print_lock_class_header(struct lock_class *class, int depth)
 
        printk("%*s->", depth, "");
        print_lock_name(class);
-       printk(" ops: %lu", class->ops);
-       printk(" {\n");
+       printk(KERN_CONT " ops: %lu", class->ops);
+       printk(KERN_CONT " {\n");
 
        for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
                if (class->usage_mask & (1 << bit)) {
                        int len = depth;
 
                        len += printk("%*s   %s", depth, "", usage_str[bit]);
-                       len += printk(" at:\n");
+                       len += printk(KERN_CONT " at:\n");
                        print_stack_trace(class->usage_traces + bit, len);
                }
        }
        printk("%*s }\n", depth, "");
 
-       printk("%*s ... key      at: ",depth,"");
-       print_ip_sym((unsigned long)class->key);
+       printk("%*s ... key      at: [<%p>] %pS\n",
+               depth, "", class->key, class->key);
 }
 
 /*
@@ -1437,11 +1437,11 @@ print_irq_lock_scenario(struct lock_list *safe_entry,
        if (middle_class != unsafe_class) {
                printk("Chain exists of:\n  ");
                __print_lock_name(safe_class);
-               printk(" --> ");
+               printk(KERN_CONT " --> ");
                __print_lock_name(middle_class);
-               printk(" --> ");
+               printk(KERN_CONT " --> ");
                __print_lock_name(unsafe_class);
-               printk("\n\n");
+               printk(KERN_CONT "\n\n");
        }
 
        printk(" Possible interrupt unsafe locking scenario:\n\n");
@@ -1449,18 +1449,18 @@ print_irq_lock_scenario(struct lock_list *safe_entry,
        printk("       ----                    ----\n");
        printk("  lock(");
        __print_lock_name(unsafe_class);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("                               local_irq_disable();\n");
        printk("                               lock(");
        __print_lock_name(safe_class);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("                               lock(");
        __print_lock_name(middle_class);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("  <Interrupt>\n");
        printk("    lock(");
        __print_lock_name(safe_class);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("\n *** DEADLOCK ***\n\n");
 }
 
@@ -1497,9 +1497,9 @@ print_bad_irq_dependency(struct task_struct *curr,
        print_lock(prev);
        printk("which would create a new lock dependency:\n");
        print_lock_name(hlock_class(prev));
-       printk(" ->");
+       printk(KERN_CONT " ->");
        print_lock_name(hlock_class(next));
-       printk("\n");
+       printk(KERN_CONT "\n");
 
        printk("\nbut this new dependency connects a %s-irq-safe lock:\n",
                irqclass);
@@ -1521,8 +1521,7 @@ print_bad_irq_dependency(struct task_struct *curr,
 
        lockdep_print_held_locks(curr);
 
-       printk("\nthe dependencies between %s-irq-safe lock", irqclass);
-       printk(" and the holding lock:\n");
+       printk("\nthe dependencies between %s-irq-safe lock and the holding lock:\n", irqclass);
        if (!save_trace(&prev_root->trace))
                return 0;
        print_shortest_lock_dependencies(backwards_entry, prev_root);
@@ -1694,10 +1693,10 @@ print_deadlock_scenario(struct held_lock *nxt,
        printk("       ----\n");
        printk("  lock(");
        __print_lock_name(prev);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("  lock(");
        __print_lock_name(next);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("\n *** DEADLOCK ***\n\n");
        printk(" May be due to missing lock nesting notation\n\n");
 }
@@ -1891,9 +1890,9 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
                graph_unlock();
                printk("\n new dependency: ");
                print_lock_name(hlock_class(prev));
-               printk(" => ");
+               printk(KERN_CONT " => ");
                print_lock_name(hlock_class(next));
-               printk("\n");
+               printk(KERN_CONT "\n");
                dump_stack();
                return graph_lock();
        }
@@ -2343,11 +2342,11 @@ print_usage_bug_scenario(struct held_lock *lock)
        printk("       ----\n");
        printk("  lock(");
        __print_lock_name(class);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("  <Interrupt>\n");
        printk("    lock(");
        __print_lock_name(class);
-       printk(");\n");
+       printk(KERN_CONT ");\n");
        printk("\n *** DEADLOCK ***\n\n");
 }
 
@@ -2522,14 +2521,18 @@ check_usage_backwards(struct task_struct *curr, struct held_lock *this,
 void print_irqtrace_events(struct task_struct *curr)
 {
        printk("irq event stamp: %u\n", curr->irq_events);
-       printk("hardirqs last  enabled at (%u): ", curr->hardirq_enable_event);
-       print_ip_sym(curr->hardirq_enable_ip);
-       printk("hardirqs last disabled at (%u): ", curr->hardirq_disable_event);
-       print_ip_sym(curr->hardirq_disable_ip);
-       printk("softirqs last  enabled at (%u): ", curr->softirq_enable_event);
-       print_ip_sym(curr->softirq_enable_ip);
-       printk("softirqs last disabled at (%u): ", curr->softirq_disable_event);
-       print_ip_sym(curr->softirq_disable_ip);
+       printk("hardirqs last  enabled at (%u): [<%p>] %pS\n",
+               curr->hardirq_enable_event, (void *)curr->hardirq_enable_ip,
+               (void *)curr->hardirq_enable_ip);
+       printk("hardirqs last disabled at (%u): [<%p>] %pS\n",
+               curr->hardirq_disable_event, (void *)curr->hardirq_disable_ip,
+               (void *)curr->hardirq_disable_ip);
+       printk("softirqs last  enabled at (%u): [<%p>] %pS\n",
+               curr->softirq_enable_event, (void *)curr->softirq_enable_ip,
+               (void *)curr->softirq_enable_ip);
+       printk("softirqs last disabled at (%u): [<%p>] %pS\n",
+               curr->softirq_disable_event, (void *)curr->softirq_disable_ip,
+               (void *)curr->softirq_disable_ip);
 }
 
 static int HARDIRQ_verbose(struct lock_class *class)
@@ -3235,8 +3238,8 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        if (very_verbose(class)) {
                printk("\nacquire class [%p] %s", class->key, class->name);
                if (class->name_version > 1)
-                       printk("#%d", class->name_version);
-               printk("\n");
+                       printk(KERN_CONT "#%d", class->name_version);
+               printk(KERN_CONT "\n");
                dump_stack();
        }
 
@@ -3378,7 +3381,7 @@ print_unlock_imbalance_bug(struct task_struct *curr, struct lockdep_map *lock,
        printk("%s/%d is trying to release lock (",
                curr->comm, task_pid_nr(curr));
        print_lockdep_cache(lock);
-       printk(") at:\n");
+       printk(KERN_CONT ") at:\n");
        print_ip_sym(ip);
        printk("but there are no more locks to release!\n");
        printk("\nother info that might help us debug this:\n");
@@ -3871,7 +3874,7 @@ print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock,
        printk("%s/%d is trying to contend lock (",
                curr->comm, task_pid_nr(curr));
        print_lockdep_cache(lock);
-       printk(") at:\n");
+       printk(KERN_CONT ") at:\n");
        print_ip_sym(ip);
        printk("but there are no locks held!\n");
        printk("\nother info that might help us debug this:\n");
index 51c4b24b6328609e57e6e206814a3c3c938d8555..c2b88490d857583026a35090b62f7891446b7ba2 100644 (file)
@@ -45,6 +45,14 @@ enum {
 #define LOCKF_USED_IN_IRQ_READ \
                (LOCKF_USED_IN_HARDIRQ_READ | LOCKF_USED_IN_SOFTIRQ_READ)
 
+/*
+ * CONFIG_PROVE_LOCKING_SMALL is defined for sparc. Sparc requires .text,
+ * .data and .bss to fit in required 32MB limit for the kernel. With
+ * PROVE_LOCKING we could go over this limit and cause system boot-up problems.
+ * So, reduce the static allocations for lockdeps related structures so that
+ * everything fits in current required size limit.
+ */
+#ifdef CONFIG_PROVE_LOCKING_SMALL
 /*
  * MAX_LOCKDEP_ENTRIES is the maximum number of lock dependencies
  * we track.
@@ -54,18 +62,24 @@ enum {
  * table (if it's not there yet), and we check it for lock order
  * conflicts and deadlocks.
  */
+#define MAX_LOCKDEP_ENTRIES    16384UL
+#define MAX_LOCKDEP_CHAINS_BITS        15
+#define MAX_STACK_TRACE_ENTRIES        262144UL
+#else
 #define MAX_LOCKDEP_ENTRIES    32768UL
 
 #define MAX_LOCKDEP_CHAINS_BITS        16
-#define MAX_LOCKDEP_CHAINS     (1UL << MAX_LOCKDEP_CHAINS_BITS)
-
-#define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5)
 
 /*
  * Stack-trace: tightly packed array of stack backtrace
  * addresses. Protected by the hash_lock.
  */
 #define MAX_STACK_TRACE_ENTRIES        524288UL
+#endif
+
+#define MAX_LOCKDEP_CHAINS     (1UL << MAX_LOCKDEP_CHAINS_BITS)
+
+#define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5)
 
 extern struct list_head all_lock_classes;
 extern struct lock_chain lock_chains[];
index 1ec0f48962b33dce424d4d3f491c6a1fd76ba13d..2c49d76f96c3351c2038b630e5875066a907509b 100644 (file)
@@ -65,8 +65,72 @@ static inline void clear_rt_mutex_waiters(struct rt_mutex *lock)
 
 static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
 {
-       if (!rt_mutex_has_waiters(lock))
-               clear_rt_mutex_waiters(lock);
+       unsigned long owner, *p = (unsigned long *) &lock->owner;
+
+       if (rt_mutex_has_waiters(lock))
+               return;
+
+       /*
+        * The rbtree has no waiters enqueued, now make sure that the
+        * lock->owner still has the waiters bit set, otherwise the
+        * following can happen:
+        *
+        * CPU 0        CPU 1           CPU2
+        * l->owner=T1
+        *              rt_mutex_lock(l)
+        *              lock(l->lock)
+        *              l->owner = T1 | HAS_WAITERS;
+        *              enqueue(T2)
+        *              boost()
+        *                unlock(l->lock)
+        *              block()
+        *
+        *                              rt_mutex_lock(l)
+        *                              lock(l->lock)
+        *                              l->owner = T1 | HAS_WAITERS;
+        *                              enqueue(T3)
+        *                              boost()
+        *                                unlock(l->lock)
+        *                              block()
+        *              signal(->T2)    signal(->T3)
+        *              lock(l->lock)
+        *              dequeue(T2)
+        *              deboost()
+        *                unlock(l->lock)
+        *                              lock(l->lock)
+        *                              dequeue(T3)
+        *                               ==> wait list is empty
+        *                              deboost()
+        *                               unlock(l->lock)
+        *              lock(l->lock)
+        *              fixup_rt_mutex_waiters()
+        *                if (wait_list_empty(l) {
+        *                  l->owner = owner
+        *                  owner = l->owner & ~HAS_WAITERS;
+        *                    ==> l->owner = T1
+        *                }
+        *                              lock(l->lock)
+        * rt_mutex_unlock(l)           fixup_rt_mutex_waiters()
+        *                                if (wait_list_empty(l) {
+        *                                  owner = l->owner & ~HAS_WAITERS;
+        * cmpxchg(l->owner, T1, NULL)
+        *  ===> Success (l->owner = NULL)
+        *
+        *                                  l->owner = owner
+        *                                    ==> l->owner = T1
+        *                                }
+        *
+        * With the check for the waiter bit in place T3 on CPU2 will not
+        * overwrite. All tasks fiddling with the waiters bit are
+        * serialized by l->lock, so nothing else can modify the waiters
+        * bit. If the bit is set then nothing can change l->owner either
+        * so the simple RMW is safe. The cmpxchg() will simply fail if it
+        * happens in the middle of the RMW because the waiters bit is
+        * still set.
+        */
+       owner = READ_ONCE(*p);
+       if (owner & RT_MUTEX_HAS_WAITERS)
+               WRITE_ONCE(*p, owner & ~RT_MUTEX_HAS_WAITERS);
 }
 
 /*
index 4f5f83c7d2d3515cb31dce798815e9614155d291..e317e1cbb3eba80098fa018de8573c1a1c7a86c0 100644 (file)
@@ -75,8 +75,9 @@ task_top_pi_waiter(struct task_struct *p)
 
 static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
 {
-       return (struct task_struct *)
-               ((unsigned long)lock->owner & ~RT_MUTEX_OWNER_MASKALL);
+       unsigned long owner = (unsigned long) READ_ONCE(lock->owner);
+
+       return (struct task_struct *) (owner & ~RT_MUTEX_OWNER_MASKALL);
 }
 
 /*
index f57dd63186e63c647e4566c828b1258fbcdb8724..0e54d5bf0097f57954d4848db6a830f5a0bc7072 100644 (file)
@@ -1301,8 +1301,9 @@ static int check_version(Elf_Shdr *sechdrs,
                goto bad_version;
        }
 
-       pr_warn("%s: no symbol version for %s\n", mod->name, symname);
-       return 0;
+       /* Broken toolchain. Warn once, then let it go.. */
+       pr_warn_once("%s: no symbol version for %s\n", mod->name, symname);
+       return 1;
 
 bad_version:
        pr_warn("%s: disagrees about version of symbol %s\n",
index 1e7f5da648d991d2fbb69f0022fce67cea3b8b5e..6ccb08f57fcb431d26b266163f53b321b2782bd8 100644 (file)
@@ -498,9 +498,9 @@ static int enter_state(suspend_state_t state)
 
 #ifndef CONFIG_SUSPEND_SKIP_SYNC
        trace_suspend_resume(TPS("sync_filesystems"), 0, true);
-       printk(KERN_INFO "PM: Syncing filesystems ... ");
+       pr_info("PM: Syncing filesystems ... ");
        sys_sync();
-       printk("done.\n");
+       pr_cont("done.\n");
        trace_suspend_resume(TPS("sync_filesystems"), 0, false);
 #endif
 
index 084452e34a125ff24da375e6dce25c1224b46310..bdff5ed57f10a5ef57a015856830471422f3918a 100644 (file)
@@ -203,8 +203,10 @@ static int __init test_suspend(void)
 
        /* RTCs have initialized by now too ... can we use one? */
        dev = class_find_device(rtc_class, NULL, NULL, has_wakealarm);
-       if (dev)
+       if (dev) {
                rtc = rtc_class_open(dev_name(dev));
+               put_device(dev);
+       }
        if (!rtc) {
                printk(warn_no_rtc);
                return 0;
index d5e3973154739f9453926f28e71ec7e20ba753bb..f7a55e9ff2f7621c2403d6bf28c6f8b88d1120f2 100644 (file)
@@ -253,17 +253,6 @@ static int preferred_console = -1;
 int console_set_on_cmdline;
 EXPORT_SYMBOL(console_set_on_cmdline);
 
-#ifdef CONFIG_OF
-static bool of_specified_console;
-
-void console_set_by_of(void)
-{
-       of_specified_console = true;
-}
-#else
-# define of_specified_console false
-#endif
-
 /* Flag: console code may call schedule() */
 static int console_may_schedule;
 
@@ -794,8 +783,6 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
        return ret;
 }
 
-static void cont_flush(void);
-
 static ssize_t devkmsg_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
@@ -811,7 +798,6 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
        if (ret)
                return ret;
        raw_spin_lock_irq(&logbuf_lock);
-       cont_flush();
        while (user->seq == log_next_seq) {
                if (file->f_flags & O_NONBLOCK) {
                        ret = -EAGAIN;
@@ -874,7 +860,6 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
                return -ESPIPE;
 
        raw_spin_lock_irq(&logbuf_lock);
-       cont_flush();
        switch (whence) {
        case SEEK_SET:
                /* the first record */
@@ -913,7 +898,6 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
        poll_wait(file, &log_wait, wait);
 
        raw_spin_lock_irq(&logbuf_lock);
-       cont_flush();
        if (user->seq < log_next_seq) {
                /* return error when data has vanished underneath us */
                if (user->seq < log_first_seq)
@@ -1300,7 +1284,6 @@ static int syslog_print(char __user *buf, int size)
                size_t skip;
 
                raw_spin_lock_irq(&logbuf_lock);
-               cont_flush();
                if (syslog_seq < log_first_seq) {
                        /* messages are gone, move to first one */
                        syslog_seq = log_first_seq;
@@ -1360,7 +1343,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                return -ENOMEM;
 
        raw_spin_lock_irq(&logbuf_lock);
-       cont_flush();
        if (buf) {
                u64 next_seq;
                u64 seq;
@@ -1522,7 +1504,6 @@ int do_syslog(int type, char __user *buf, int len, int source)
        /* Number of chars in the log buffer */
        case SYSLOG_ACTION_SIZE_UNREAD:
                raw_spin_lock_irq(&logbuf_lock);
-               cont_flush();
                if (syslog_seq < log_first_seq) {
                        /* messages are gone, move to first one */
                        syslog_seq = log_first_seq;
@@ -1769,6 +1750,10 @@ static size_t log_output(int facility, int level, enum log_flags lflags, const c
                cont_flush();
        }
 
+       /* Skip empty continuation lines that couldn't be added - they just flush */
+       if (!text_len && (lflags & LOG_CONT))
+               return 0;
+
        /* If it doesn't end in a newline, try to buffer the current line */
        if (!(lflags & LOG_NEWLINE)) {
                if (cont_add(facility, level, lflags, text, text_len))
@@ -2653,7 +2638,7 @@ void register_console(struct console *newcon)
         *      didn't select a console we take the first one
         *      that registers here.
         */
-       if (preferred_console < 0 && !of_specified_console) {
+       if (preferred_console < 0) {
                if (newcon->index < 0)
                        newcon->index = 0;
                if (newcon->setup == NULL ||
@@ -3035,7 +3020,6 @@ void kmsg_dump(enum kmsg_dump_reason reason)
                dumper->active = true;
 
                raw_spin_lock_irqsave(&logbuf_lock, flags);
-               cont_flush();
                dumper->cur_seq = clear_seq;
                dumper->cur_idx = clear_idx;
                dumper->next_seq = log_next_seq;
@@ -3126,7 +3110,6 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
        bool ret;
 
        raw_spin_lock_irqsave(&logbuf_lock, flags);
-       cont_flush();
        ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
        raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 
@@ -3169,7 +3152,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
                goto out;
 
        raw_spin_lock_irqsave(&logbuf_lock, flags);
-       cont_flush();
        if (dumper->cur_seq < log_first_seq) {
                /* messages are gone, move to first available one */
                dumper->cur_seq = log_first_seq;
index 2a99027312a6af6773027e20029752efddc418e3..e6474f7272ec2ce96c95532ea906da113acd5354 100644 (file)
@@ -537,7 +537,7 @@ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst
                int this_len, retval;
 
                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
-               retval = access_process_vm(tsk, src, buf, this_len, 0);
+               retval = access_process_vm(tsk, src, buf, this_len, FOLL_FORCE);
                if (!retval) {
                        if (copied)
                                break;
@@ -564,7 +564,8 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds
                this_len = (len > sizeof(buf)) ? sizeof(buf) : len;
                if (copy_from_user(buf, src, this_len))
                        return -EFAULT;
-               retval = access_process_vm(tsk, dst, buf, this_len, 1);
+               retval = access_process_vm(tsk, dst, buf, this_len,
+                               FOLL_FORCE | FOLL_WRITE);
                if (!retval) {
                        if (copied)
                                break;
@@ -1127,7 +1128,7 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr,
        unsigned long tmp;
        int copied;
 
-       copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0);
+       copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), FOLL_FORCE);
        if (copied != sizeof(tmp))
                return -EIO;
        return put_user(tmp, (unsigned long __user *)data);
@@ -1138,7 +1139,8 @@ int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr,
 {
        int copied;
 
-       copied = access_process_vm(tsk, addr, &data, sizeof(data), 1);
+       copied = access_process_vm(tsk, addr, &data, sizeof(data),
+                       FOLL_FORCE | FOLL_WRITE);
        return (copied == sizeof(data)) ? 0 : -EIO;
 }
 
@@ -1155,7 +1157,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
        switch (request) {
        case PTRACE_PEEKTEXT:
        case PTRACE_PEEKDATA:
-               ret = access_process_vm(child, addr, &word, sizeof(word), 0);
+               ret = access_process_vm(child, addr, &word, sizeof(word),
+                               FOLL_FORCE);
                if (ret != sizeof(word))
                        ret = -EIO;
                else
@@ -1164,7 +1167,8 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
 
        case PTRACE_POKETEXT:
        case PTRACE_POKEDATA:
-               ret = access_process_vm(child, addr, &data, sizeof(data), 1);
+               ret = access_process_vm(child, addr, &data, sizeof(data),
+                               FOLL_FORCE | FOLL_WRITE);
                ret = (ret != sizeof(data) ? -EIO : 0);
                break;
 
index a5d966cb889175d5b196283341b1cead20f20603..da39489d2d80e9b8f6781610e97c23ec0014f45b 100644 (file)
@@ -111,10 +111,13 @@ bool task_wants_autogroup(struct task_struct *p, struct task_group *tg)
 {
        if (tg != &root_task_group)
                return false;
-
        /*
-        * We can only assume the task group can't go away on us if
-        * autogroup_move_group() can see us on ->thread_group list.
+        * If we race with autogroup_move_group() the caller can use the old
+        * value of signal->autogroup but in this case sched_move_task() will
+        * be called again before autogroup_kref_put().
+        *
+        * However, there is no way sched_autogroup_exit_task() could tell us
+        * to avoid autogroup->tg, so we abuse PF_EXITING flag for this case.
         */
        if (p->flags & PF_EXITING)
                return false;
@@ -122,6 +125,16 @@ bool task_wants_autogroup(struct task_struct *p, struct task_group *tg)
        return true;
 }
 
+void sched_autogroup_exit_task(struct task_struct *p)
+{
+       /*
+        * We are going to call exit_notify() and autogroup_move_group() can't
+        * see this thread after that: we can no longer use signal->autogroup.
+        * See the PF_EXITING check in task_wants_autogroup().
+        */
+       sched_move_task(p);
+}
+
 static void
 autogroup_move_group(struct task_struct *p, struct autogroup *ag)
 {
@@ -138,13 +151,20 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag)
        }
 
        p->signal->autogroup = autogroup_kref_get(ag);
-
-       if (!READ_ONCE(sysctl_sched_autogroup_enabled))
-               goto out;
-
+       /*
+        * We can't avoid sched_move_task() after we changed signal->autogroup,
+        * this process can already run with task_group() == prev->tg or we can
+        * race with cgroup code which can read autogroup = prev under rq->lock.
+        * In the latter case for_each_thread() can not miss a migrating thread,
+        * cpu_cgroup_attach() must not be possible after cgroup_exit() and it
+        * can't be removed from thread list, we hold ->siglock.
+        *
+        * If an exiting thread was already removed from thread list we rely on
+        * sched_autogroup_exit_task().
+        */
        for_each_thread(p, t)
                sched_move_task(t);
-out:
+
        unlock_task_sighand(p, &flags);
        autogroup_kref_put(prev);
 }
@@ -192,6 +212,7 @@ int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
 {
        static unsigned long next = INITIAL_JIFFIES;
        struct autogroup *ag;
+       unsigned long shares;
        int err;
 
        if (nice < MIN_NICE || nice > MAX_NICE)
@@ -210,9 +231,10 @@ int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
 
        next = HZ / 10 + jiffies;
        ag = autogroup_task_get(p);
+       shares = scale_load(sched_prio_to_weight[nice + 20]);
 
        down_write(&ag->lock);
-       err = sched_group_set_shares(ag->tg, sched_prio_to_weight[nice + 20]);
+       err = sched_group_set_shares(ag->tg, shares);
        if (!err)
                ag->nice = nice;
        up_write(&ag->lock);
index 94732d1ab00ab9d9afdebad41642e279249776cb..154fd689fe02e910be7abe1102dbac32b5b50a8a 100644 (file)
@@ -5192,21 +5192,14 @@ void sched_show_task(struct task_struct *p)
        int ppid;
        unsigned long state = p->state;
 
+       if (!try_get_task_stack(p))
+               return;
        if (state)
                state = __ffs(state) + 1;
        printk(KERN_INFO "%-15.15s %c", p->comm,
                state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?');
-#if BITS_PER_LONG == 32
-       if (state == TASK_RUNNING)
-               printk(KERN_CONT " running  ");
-       else
-               printk(KERN_CONT " %08lx ", thread_saved_pc(p));
-#else
        if (state == TASK_RUNNING)
                printk(KERN_CONT "  running task    ");
-       else
-               printk(KERN_CONT " %016lx ", thread_saved_pc(p));
-#endif
 #ifdef CONFIG_DEBUG_STACK_USAGE
        free = stack_not_used(p);
 #endif
@@ -5221,6 +5214,7 @@ void sched_show_task(struct task_struct *p)
 
        print_worker_info(KERN_INFO, p);
        show_stack(p, NULL);
+       put_task_stack(p);
 }
 
 void show_state_filter(unsigned long state_filter)
@@ -7515,11 +7509,27 @@ static struct kmem_cache *task_group_cache __read_mostly;
 DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
 DECLARE_PER_CPU(cpumask_var_t, select_idle_mask);
 
+#define WAIT_TABLE_BITS 8
+#define WAIT_TABLE_SIZE (1 << WAIT_TABLE_BITS)
+static wait_queue_head_t bit_wait_table[WAIT_TABLE_SIZE] __cacheline_aligned;
+
+wait_queue_head_t *bit_waitqueue(void *word, int bit)
+{
+       const int shift = BITS_PER_LONG == 32 ? 5 : 6;
+       unsigned long val = (unsigned long)word << shift | bit;
+
+       return bit_wait_table + hash_long(val, WAIT_TABLE_BITS);
+}
+EXPORT_SYMBOL(bit_waitqueue);
+
 void __init sched_init(void)
 {
        int i, j;
        unsigned long alloc_size = 0, ptr;
 
+       for (i = 0; i < WAIT_TABLE_SIZE; i++)
+               init_waitqueue_head(bit_wait_table + i);
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
        alloc_size += 2 * nr_cpu_ids * sizeof(void **);
 #endif
index 2d4ad72f8f3c8c585f0b8876d2255614944cf157..c242944f5cbd560223ce91990ca92666460110bf 100644 (file)
@@ -690,7 +690,14 @@ void init_entity_runnable_average(struct sched_entity *se)
         * will definitely be update (after enqueue).
         */
        sa->period_contrib = 1023;
-       sa->load_avg = scale_load_down(se->load.weight);
+       /*
+        * Tasks are intialized with full load to be seen as heavy tasks until
+        * they get a chance to stabilize to their real load level.
+        * Group entities are intialized with zero load to reflect the fact that
+        * nothing has been attached to the task group yet.
+        */
+       if (entity_is_task(se))
+               sa->load_avg = scale_load_down(se->load.weight);
        sa->load_sum = sa->load_avg * LOAD_AVG_MAX;
        /*
         * At this point, util_avg won't be used in select_task_rq_fair anyway
@@ -5471,13 +5478,18 @@ static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd
  */
 static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int target)
 {
-       struct sched_domain *this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc));
-       u64 avg_idle = this_rq()->avg_idle;
-       u64 avg_cost = this_sd->avg_scan_cost;
+       struct sched_domain *this_sd;
+       u64 avg_cost, avg_idle = this_rq()->avg_idle;
        u64 time, cost;
        s64 delta;
        int cpu, wrap;
 
+       this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc));
+       if (!this_sd)
+               return -1;
+
+       avg_cost = this_sd->avg_scan_cost;
+
        /*
         * Due to large variance we need a large fuzz factor; hackbench in
         * particularly is sensitive here.
@@ -8827,7 +8839,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
 {
        struct sched_entity *se;
        struct cfs_rq *cfs_rq;
-       struct rq *rq;
        int i;
 
        tg->cfs_rq = kzalloc(sizeof(cfs_rq) * nr_cpu_ids, GFP_KERNEL);
@@ -8842,8 +8853,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
        init_cfs_bandwidth(tg_cfs_bandwidth(tg));
 
        for_each_possible_cpu(i) {
-               rq = cpu_rq(i);
-
                cfs_rq = kzalloc_node(sizeof(struct cfs_rq),
                                      GFP_KERNEL, cpu_to_node(i));
                if (!cfs_rq)
index 4f7053579fe3c9e473bfb9854f959a874e9566ea..9453efe9b25a64bd4aefceae8e5dffef54df64f2 100644 (file)
@@ -480,16 +480,6 @@ void wake_up_bit(void *word, int bit)
 }
 EXPORT_SYMBOL(wake_up_bit);
 
-wait_queue_head_t *bit_waitqueue(void *word, int bit)
-{
-       const int shift = BITS_PER_LONG == 32 ? 5 : 6;
-       const struct zone *zone = page_zone(virt_to_page(word));
-       unsigned long val = (unsigned long)word << shift | bit;
-
-       return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
-}
-EXPORT_SYMBOL(bit_waitqueue);
-
 /*
  * Manipulate the atomic_t address to produce a better bit waitqueue table hash
  * index (we're keying off bit -1, but that would produce a horrible hash
index 1bf81ef913755ae797c90e2affc3330f54d3a7df..744fa611cae06b26d89a04e915f0d7fadf37035b 100644 (file)
@@ -58,7 +58,7 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp
 DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
 const char * const softirq_to_name[NR_SOFTIRQS] = {
-       "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL",
+       "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL",
        "TASKLET", "SCHED", "HRTIMER", "RCU"
 };
 
index b3f05ee20d1845736580d3c4fbd55d67e7fc3b51..cbb387a265db01a7bde8d6576316cdeffa6f1103 100644 (file)
@@ -54,7 +54,11 @@ static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1
        [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
        [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
 
-static const struct nla_policy cgroupstats_cmd_get_policy[CGROUPSTATS_CMD_ATTR_MAX+1] = {
+/*
+ * We have to use TASKSTATS_CMD_ATTR_MAX here, it is the maxattr in the family.
+ * Make sure they are always aligned.
+ */
+static const struct nla_policy cgroupstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
        [CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 },
 };
 
index c3aad685bbc036cc2f03672085aedd9dc9c8fb86..12dd190634ab3e0617ac260133818523f142f8a2 100644 (file)
@@ -542,7 +542,6 @@ static int alarm_clock_get(clockid_t which_clock, struct timespec *tp)
 static int alarm_timer_create(struct k_itimer *new_timer)
 {
        enum  alarmtimer_type type;
-       struct alarm_base *base;
 
        if (!alarmtimer_get_rtcdev())
                return -ENOTSUPP;
@@ -551,7 +550,6 @@ static int alarm_timer_create(struct k_itimer *new_timer)
                return -EPERM;
 
        type = clock2alarm(new_timer->it_clock);
-       base = &alarm_bases[type];
        alarm_init(&new_timer->it.alarm.alarmtimer, type, alarm_handle_timer);
        return 0;
 }
index 2d47980a1bc423df44e8e1324537f4e185b338ae..c611c47de8849b5ac68a8085d85dcd86e143d907 100644 (file)
@@ -878,7 +878,7 @@ static inline struct timer_base *get_timer_base(u32 tflags)
 
 #ifdef CONFIG_NO_HZ_COMMON
 static inline struct timer_base *
-__get_target_base(struct timer_base *base, unsigned tflags)
+get_target_base(struct timer_base *base, unsigned tflags)
 {
 #ifdef CONFIG_SMP
        if ((tflags & TIMER_PINNED) || !base->migration_enabled)
@@ -891,25 +891,27 @@ __get_target_base(struct timer_base *base, unsigned tflags)
 
 static inline void forward_timer_base(struct timer_base *base)
 {
+       unsigned long jnow = READ_ONCE(jiffies);
+
        /*
         * We only forward the base when it's idle and we have a delta between
         * base clock and jiffies.
         */
-       if (!base->is_idle || (long) (jiffies - base->clk) < 2)
+       if (!base->is_idle || (long) (jnow - base->clk) < 2)
                return;
 
        /*
         * If the next expiry value is > jiffies, then we fast forward to
         * jiffies otherwise we forward to the next expiry value.
         */
-       if (time_after(base->next_expiry, jiffies))
-               base->clk = jiffies;
+       if (time_after(base->next_expiry, jnow))
+               base->clk = jnow;
        else
                base->clk = base->next_expiry;
 }
 #else
 static inline struct timer_base *
-__get_target_base(struct timer_base *base, unsigned tflags)
+get_target_base(struct timer_base *base, unsigned tflags)
 {
        return get_timer_this_cpu_base(tflags);
 }
@@ -917,14 +919,6 @@ __get_target_base(struct timer_base *base, unsigned tflags)
 static inline void forward_timer_base(struct timer_base *base) { }
 #endif
 
-static inline struct timer_base *
-get_target_base(struct timer_base *base, unsigned tflags)
-{
-       struct timer_base *target = __get_target_base(base, tflags);
-
-       forward_timer_base(target);
-       return target;
-}
 
 /*
  * We are using hashed locking: Holding per_cpu(timer_bases[x]).lock means
@@ -943,7 +937,14 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
 {
        for (;;) {
                struct timer_base *base;
-               u32 tf = timer->flags;
+               u32 tf;
+
+               /*
+                * We need to use READ_ONCE() here, otherwise the compiler
+                * might re-read @tf between the check for TIMER_MIGRATING
+                * and spin_lock().
+                */
+               tf = READ_ONCE(timer->flags);
 
                if (!(tf & TIMER_MIGRATING)) {
                        base = get_timer_base(tf);
@@ -964,6 +965,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
        unsigned long clk = 0, flags;
        int ret = 0;
 
+       BUG_ON(!timer->function);
+
        /*
         * This is a common optimization triggered by the networking code - if
         * the timer is re-modified to have the same timeout or ends up in the
@@ -972,13 +975,16 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
        if (timer_pending(timer)) {
                if (timer->expires == expires)
                        return 1;
+
                /*
-                * Take the current timer_jiffies of base, but without holding
-                * the lock!
+                * We lock timer base and calculate the bucket index right
+                * here. If the timer ends up in the same bucket, then we
+                * just update the expiry time and avoid the whole
+                * dequeue/enqueue dance.
                 */
-               base = get_timer_base(timer->flags);
-               clk = base->clk;
+               base = lock_timer_base(timer, &flags);
 
+               clk = base->clk;
                idx = calc_wheel_index(expires, clk);
 
                /*
@@ -988,14 +994,14 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
                 */
                if (idx == timer_get_idx(timer)) {
                        timer->expires = expires;
-                       return 1;
+                       ret = 1;
+                       goto out_unlock;
                }
+       } else {
+               base = lock_timer_base(timer, &flags);
        }
 
        timer_stats_timer_set_start_info(timer);
-       BUG_ON(!timer->function);
-
-       base = lock_timer_base(timer, &flags);
 
        ret = detach_if_pending(timer, base, false);
        if (!ret && pending_only)
@@ -1025,12 +1031,16 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
                }
        }
 
+       /* Try to forward a stale timer base clock */
+       forward_timer_base(base);
+
        timer->expires = expires;
        /*
         * If 'idx' was calculated above and the base time did not advance
-        * between calculating 'idx' and taking the lock, only enqueue_timer()
-        * and trigger_dyntick_cpu() is required. Otherwise we need to
-        * (re)calculate the wheel index via internal_add_timer().
+        * between calculating 'idx' and possibly switching the base, only
+        * enqueue_timer() and trigger_dyntick_cpu() is required. Otherwise
+        * we need to (re)calculate the wheel index via
+        * internal_add_timer().
         */
        if (idx != UINT_MAX && clk == base->clk) {
                enqueue_timer(base, timer, idx);
@@ -1510,12 +1520,16 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
        is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA);
        base->next_expiry = nextevt;
        /*
-        * We have a fresh next event. Check whether we can forward the base:
+        * We have a fresh next event. Check whether we can forward the
+        * base. We can only do that when @basej is past base->clk
+        * otherwise we might rewind base->clk.
         */
-       if (time_after(nextevt, jiffies))
-               base->clk = jiffies;
-       else if (time_after(nextevt, base->clk))
-               base->clk = nextevt;
+       if (time_after(basej, base->clk)) {
+               if (time_after(nextevt, basej))
+                       base->clk = basej;
+               else if (time_after(nextevt, base->clk))
+                       base->clk = nextevt;
+       }
 
        if (time_before_eq(nextevt, basej)) {
                expires = basem;
index 2050a7652a86afa140ac94c3eb4de604aea80449..da87b3cba5b39aabb264dcf046b500c12259b0a0 100644 (file)
@@ -1862,6 +1862,10 @@ static int __ftrace_hash_update_ipmodify(struct ftrace_ops *ops,
 
        /* Update rec->flags */
        do_for_each_ftrace_rec(pg, rec) {
+
+               if (rec->flags & FTRACE_FL_DISABLED)
+                       continue;
+
                /* We need to update only differences of filter_hash */
                in_old = !!ftrace_lookup_ip(old_hash, rec->ip);
                in_new = !!ftrace_lookup_ip(new_hash, rec->ip);
@@ -1884,6 +1888,10 @@ rollback:
 
        /* Roll back what we did above */
        do_for_each_ftrace_rec(pg, rec) {
+
+               if (rec->flags & FTRACE_FL_DISABLED)
+                       continue;
+
                if (rec == end)
                        goto err_out;
 
@@ -2397,6 +2405,10 @@ void __weak ftrace_replace_code(int enable)
                return;
 
        do_for_each_ftrace_rec(pg, rec) {
+
+               if (rec->flags & FTRACE_FL_DISABLED)
+                       continue;
+
                failed = __ftrace_replace_code(rec, enable);
                if (failed) {
                        ftrace_bug(failed, rec);
@@ -2763,7 +2775,7 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
                struct dyn_ftrace *rec;
 
                do_for_each_ftrace_rec(pg, rec) {
-                       if (FTRACE_WARN_ON_ONCE(rec->flags))
+                       if (FTRACE_WARN_ON_ONCE(rec->flags & ~FTRACE_FL_DISABLED))
                                pr_warn("  %pS flags:%lx\n",
                                        (void *)rec->ip, rec->flags);
                } while_for_each_ftrace_rec();
@@ -3598,6 +3610,10 @@ match_records(struct ftrace_hash *hash, char *func, int len, char *mod)
                goto out_unlock;
 
        do_for_each_ftrace_rec(pg, rec) {
+
+               if (rec->flags & FTRACE_FL_DISABLED)
+                       continue;
+
                if (ftrace_match_record(rec, &func_g, mod_match, exclude_mod)) {
                        ret = enter_record(hash, rec, clear_filter);
                        if (ret < 0) {
@@ -3793,6 +3809,9 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 
        do_for_each_ftrace_rec(pg, rec) {
 
+               if (rec->flags & FTRACE_FL_DISABLED)
+                       continue;
+
                if (!ftrace_match_record(rec, &func_g, NULL, 0))
                        continue;
 
@@ -4685,6 +4704,9 @@ ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer)
 
        do_for_each_ftrace_rec(pg, rec) {
 
+               if (rec->flags & FTRACE_FL_DISABLED)
+                       continue;
+
                if (ftrace_match_record(rec, &func_g, NULL, 0)) {
                        /* if it is in the array */
                        exists = false;
index 33bc56cf60d71fc81f5f5981100406e1c7a91b10..a6c8db1d62f65ffb2ec6a53011ce0b675f9fb7d4 100644 (file)
@@ -198,6 +198,7 @@ config FRAME_WARN
        int "Warn for stack frames larger than (needs gcc 4.4)"
        range 0 8192
        default 0 if KASAN
+       default 2048 if GCC_PLUGIN_LATENT_ENTROPY
        default 1024 if !64BIT
        default 2048 if 64BIT
        help
@@ -1084,6 +1085,9 @@ config PROVE_LOCKING
 
         For more details, see Documentation/locking/lockdep-design.txt.
 
+config PROVE_LOCKING_SMALL
+       bool
+
 config LOCKDEP
        bool
        depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
index a8e12601eb37dca5694faa1a5bfc9cb5e45497f1..056052dc8e911f31f20bd5aff4824c94dd9f5e83 100644 (file)
@@ -362,6 +362,7 @@ void debug_object_init(void *addr, struct debug_obj_descr *descr)
 
        __debug_object_init(addr, descr, 0);
 }
+EXPORT_SYMBOL_GPL(debug_object_init);
 
 /**
  * debug_object_init_on_stack - debug checks when an object on stack is
@@ -376,6 +377,7 @@ void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr)
 
        __debug_object_init(addr, descr, 1);
 }
+EXPORT_SYMBOL_GPL(debug_object_init_on_stack);
 
 /**
  * debug_object_activate - debug checks when an object is activated
@@ -449,6 +451,7 @@ int debug_object_activate(void *addr, struct debug_obj_descr *descr)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(debug_object_activate);
 
 /**
  * debug_object_deactivate - debug checks when an object is deactivated
@@ -496,6 +499,7 @@ void debug_object_deactivate(void *addr, struct debug_obj_descr *descr)
 
        raw_spin_unlock_irqrestore(&db->lock, flags);
 }
+EXPORT_SYMBOL_GPL(debug_object_deactivate);
 
 /**
  * debug_object_destroy - debug checks when an object is destroyed
@@ -542,6 +546,7 @@ void debug_object_destroy(void *addr, struct debug_obj_descr *descr)
 out_unlock:
        raw_spin_unlock_irqrestore(&db->lock, flags);
 }
+EXPORT_SYMBOL_GPL(debug_object_destroy);
 
 /**
  * debug_object_free - debug checks when an object is freed
@@ -582,6 +587,7 @@ void debug_object_free(void *addr, struct debug_obj_descr *descr)
 out_unlock:
        raw_spin_unlock_irqrestore(&db->lock, flags);
 }
+EXPORT_SYMBOL_GPL(debug_object_free);
 
 /**
  * debug_object_assert_init - debug checks when object should be init-ed
@@ -626,6 +632,7 @@ void debug_object_assert_init(void *addr, struct debug_obj_descr *descr)
 
        raw_spin_unlock_irqrestore(&db->lock, flags);
 }
+EXPORT_SYMBOL_GPL(debug_object_assert_init);
 
 /**
  * debug_object_active_state - debug checks object usage state machine
@@ -673,6 +680,7 @@ debug_object_active_state(void *addr, struct debug_obj_descr *descr,
 
        raw_spin_unlock_irqrestore(&db->lock, flags);
 }
+EXPORT_SYMBOL_GPL(debug_object_active_state);
 
 #ifdef CONFIG_DEBUG_OBJECTS_FREE
 static void __debug_check_no_obj_freed(const void *address, unsigned long size)
index 0a1139644d328a92ae346ee6fa723d7e18085c75..144fe6b1a03ea536893f6e35d153a895a238b67d 100644 (file)
@@ -292,7 +292,7 @@ unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size,
        struct gen_pool_chunk *chunk;
        unsigned long addr = 0;
        int order = pool->min_alloc_order;
-       int nbits, start_bit = 0, end_bit, remain;
+       int nbits, start_bit, end_bit, remain;
 
 #ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
        BUG_ON(in_nmi());
@@ -307,6 +307,7 @@ unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size,
                if (size > atomic_read(&chunk->avail))
                        continue;
 
+               start_bit = 0;
                end_bit = chunk_size(chunk) >> order;
 retry:
                start_bit = algo(chunk->bits, end_bit, start_bit,
index f0c7f1481baeefe30f14820ef9a2782a1541a175..f2bd21b93dfca464ae24bb18c6492bd8c7f1eb88 100644 (file)
@@ -683,10 +683,11 @@ static void pipe_advance(struct iov_iter *i, size_t size)
        struct pipe_inode_info *pipe = i->pipe;
        struct pipe_buffer *buf;
        int idx = i->idx;
-       size_t off = i->iov_offset;
+       size_t off = i->iov_offset, orig_sz;
        
        if (unlikely(i->count < size))
                size = i->count;
+       orig_sz = size;
 
        if (size) {
                if (off) /* make it relative to the beginning of buffer */
@@ -713,6 +714,7 @@ static void pipe_advance(struct iov_iter *i, size_t size)
                        pipe->nrbufs--;
                }
        }
+       i->count -= orig_sz;
 }
 
 void iov_iter_advance(struct iov_iter *i, size_t size)
index 872a15a2a6374017af2bc0f8a446f86736f9b45e..f3a217ea03888dcdad20e12fdc8ef196b1897456 100644 (file)
@@ -980,23 +980,23 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
 #ifndef CONFIG_PROVE_LOCKING
        if (expected == FAILURE && debug_locks) {
                expected_testcase_failures++;
-               printk("failed|");
+               pr_cont("failed|");
        }
        else
 #endif
        if (debug_locks != expected) {
                unexpected_testcase_failures++;
-               printk("FAILED|");
+               pr_cont("FAILED|");
 
                dump_stack();
        } else {
                testcase_successes++;
-               printk("  ok  |");
+               pr_cont("  ok  |");
        }
        testcase_total++;
 
        if (debug_locks_verbose)
-               printk(" lockclass mask: %x, debug_locks: %d, expected: %d\n",
+               pr_cont(" lockclass mask: %x, debug_locks: %d, expected: %d\n",
                        lockclass_mask, debug_locks, expected);
        /*
         * Some tests (e.g. double-unlock) might corrupt the preemption
@@ -1021,26 +1021,26 @@ static inline void print_testname(const char *testname)
 #define DO_TESTCASE_1(desc, name, nr)                          \
        print_testname(desc"/"#nr);                             \
        dotest(name##_##nr, SUCCESS, LOCKTYPE_RWLOCK);          \
-       printk("\n");
+       pr_cont("\n");
 
 #define DO_TESTCASE_1B(desc, name, nr)                         \
        print_testname(desc"/"#nr);                             \
        dotest(name##_##nr, FAILURE, LOCKTYPE_RWLOCK);          \
-       printk("\n");
+       pr_cont("\n");
 
 #define DO_TESTCASE_3(desc, name, nr)                          \
        print_testname(desc"/"#nr);                             \
        dotest(name##_spin_##nr, FAILURE, LOCKTYPE_SPIN);       \
        dotest(name##_wlock_##nr, FAILURE, LOCKTYPE_RWLOCK);    \
        dotest(name##_rlock_##nr, SUCCESS, LOCKTYPE_RWLOCK);    \
-       printk("\n");
+       pr_cont("\n");
 
 #define DO_TESTCASE_3RW(desc, name, nr)                                \
        print_testname(desc"/"#nr);                             \
        dotest(name##_spin_##nr, FAILURE, LOCKTYPE_SPIN|LOCKTYPE_RWLOCK);\
        dotest(name##_wlock_##nr, FAILURE, LOCKTYPE_RWLOCK);    \
        dotest(name##_rlock_##nr, SUCCESS, LOCKTYPE_RWLOCK);    \
-       printk("\n");
+       pr_cont("\n");
 
 #define DO_TESTCASE_6(desc, name)                              \
        print_testname(desc);                                   \
@@ -1050,7 +1050,7 @@ static inline void print_testname(const char *testname)
        dotest(name##_mutex, FAILURE, LOCKTYPE_MUTEX);          \
        dotest(name##_wsem, FAILURE, LOCKTYPE_RWSEM);           \
        dotest(name##_rsem, FAILURE, LOCKTYPE_RWSEM);           \
-       printk("\n");
+       pr_cont("\n");
 
 #define DO_TESTCASE_6_SUCCESS(desc, name)                      \
        print_testname(desc);                                   \
@@ -1060,7 +1060,7 @@ static inline void print_testname(const char *testname)
        dotest(name##_mutex, SUCCESS, LOCKTYPE_MUTEX);          \
        dotest(name##_wsem, SUCCESS, LOCKTYPE_RWSEM);           \
        dotest(name##_rsem, SUCCESS, LOCKTYPE_RWSEM);           \
-       printk("\n");
+       pr_cont("\n");
 
 /*
  * 'read' variant: rlocks must not trigger.
@@ -1073,7 +1073,7 @@ static inline void print_testname(const char *testname)
        dotest(name##_mutex, FAILURE, LOCKTYPE_MUTEX);          \
        dotest(name##_wsem, FAILURE, LOCKTYPE_RWSEM);           \
        dotest(name##_rsem, FAILURE, LOCKTYPE_RWSEM);           \
-       printk("\n");
+       pr_cont("\n");
 
 #define DO_TESTCASE_2I(desc, name, nr)                         \
        DO_TESTCASE_1("hard-"desc, name##_hard, nr);            \
@@ -1726,25 +1726,25 @@ static void ww_tests(void)
        dotest(ww_test_fail_acquire, SUCCESS, LOCKTYPE_WW);
        dotest(ww_test_normal, SUCCESS, LOCKTYPE_WW);
        dotest(ww_test_unneeded_slow, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("ww contexts mixing");
        dotest(ww_test_two_contexts, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_diff_class, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("finishing ww context");
        dotest(ww_test_context_done_twice, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_context_unlock_twice, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_context_fini_early, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_context_lock_after_done, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("locking mismatches");
        dotest(ww_test_object_unlock_twice, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_object_lock_unbalanced, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_object_lock_stale_context, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("EDEADLK handling");
        dotest(ww_test_edeadlk_normal, SUCCESS, LOCKTYPE_WW);
@@ -1757,11 +1757,11 @@ static void ww_tests(void)
        dotest(ww_test_edeadlk_acquire_more_edeadlk_slow, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_edeadlk_acquire_wrong, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_edeadlk_acquire_wrong_slow, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("spinlock nest unlocked");
        dotest(ww_test_spin_nest_unlocked, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        printk("  -----------------------------------------------------\n");
        printk("                                 |block | try  |context|\n");
@@ -1771,25 +1771,25 @@ static void ww_tests(void)
        dotest(ww_test_context_block, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_context_try, SUCCESS, LOCKTYPE_WW);
        dotest(ww_test_context_context, SUCCESS, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("try");
        dotest(ww_test_try_block, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_try_try, SUCCESS, LOCKTYPE_WW);
        dotest(ww_test_try_context, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("block");
        dotest(ww_test_block_block, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_block_try, SUCCESS, LOCKTYPE_WW);
        dotest(ww_test_block_context, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("spinlock");
        dotest(ww_test_spin_block, FAILURE, LOCKTYPE_WW);
        dotest(ww_test_spin_try, SUCCESS, LOCKTYPE_WW);
        dotest(ww_test_spin_context, FAILURE, LOCKTYPE_WW);
-       printk("\n");
+       pr_cont("\n");
 }
 
 void locking_selftest(void)
@@ -1829,32 +1829,32 @@ void locking_selftest(void)
 
        printk("  --------------------------------------------------------------------------\n");
        print_testname("recursive read-lock");
-       printk("             |");
+       pr_cont("             |");
        dotest(rlock_AA1, SUCCESS, LOCKTYPE_RWLOCK);
-       printk("             |");
+       pr_cont("             |");
        dotest(rsem_AA1, FAILURE, LOCKTYPE_RWSEM);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("recursive read-lock #2");
-       printk("             |");
+       pr_cont("             |");
        dotest(rlock_AA1B, SUCCESS, LOCKTYPE_RWLOCK);
-       printk("             |");
+       pr_cont("             |");
        dotest(rsem_AA1B, FAILURE, LOCKTYPE_RWSEM);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("mixed read-write-lock");
-       printk("             |");
+       pr_cont("             |");
        dotest(rlock_AA2, FAILURE, LOCKTYPE_RWLOCK);
-       printk("             |");
+       pr_cont("             |");
        dotest(rsem_AA2, FAILURE, LOCKTYPE_RWSEM);
-       printk("\n");
+       pr_cont("\n");
 
        print_testname("mixed write-read-lock");
-       printk("             |");
+       pr_cont("             |");
        dotest(rlock_AA3, FAILURE, LOCKTYPE_RWLOCK);
-       printk("             |");
+       pr_cont("             |");
        dotest(rsem_AA3, FAILURE, LOCKTYPE_RWSEM);
-       printk("\n");
+       pr_cont("\n");
 
        printk("  --------------------------------------------------------------------------\n");
 
index 5464c8744ea95647beeef44efc3722161f5b224b..e24388a863a76ff47afc2a7fc3680bc6ab6e8f4e 100644 (file)
@@ -64,8 +64,13 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
        if (!esize) {
                /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
                 * depending on if MOD equals 1.  */
-               rp[0] = 1;
                res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
+               if (res->nlimbs) {
+                       if (mpi_resize(res, 1) < 0)
+                               goto enomem;
+                       rp = res->d;
+                       rp[0] = 1;
+               }
                res->sign = 0;
                goto leave;
        }
index 60f77f1d470a0589ccdeacbb52a9eb45a8a1cec1..f87d138e96724a43d219231bb98d6b1a863a0f0a 100644 (file)
@@ -50,7 +50,7 @@
                                        STACK_ALLOC_ALIGN)
 #define STACK_ALLOC_INDEX_BITS (DEPOT_STACK_BITS - \
                STACK_ALLOC_NULL_PROTECTION_BITS - STACK_ALLOC_OFFSET_BITS)
-#define STACK_ALLOC_SLABS_CAP 1024
+#define STACK_ALLOC_SLABS_CAP 8192
 #define STACK_ALLOC_MAX_SLABS \
        (((1LL << (STACK_ALLOC_INDEX_BITS)) < STACK_ALLOC_SLABS_CAP) ? \
         (1LL << (STACK_ALLOC_INDEX_BITS)) : STACK_ALLOC_SLABS_CAP)
@@ -192,6 +192,7 @@ void depot_fetch_stack(depot_stack_handle_t handle, struct stack_trace *trace)
        trace->entries = stack->entries;
        trace->skip = 0;
 }
+EXPORT_SYMBOL_GPL(depot_fetch_stack);
 
 /**
  * depot_save_stack - save stack in a stack depot.
@@ -283,3 +284,4 @@ exit:
 fast_exit:
        return retval;
 }
+EXPORT_SYMBOL_GPL(depot_save_stack);
index 94346b4d8984c5cfa88743be66b1880b929e4a60..0362da0b66c352e4cb3eb96748fe2db4955d6b11 100644 (file)
@@ -4831,7 +4831,7 @@ static struct bpf_test tests[] = {
                { },
                INTERNAL,
                { 0x34 },
-               { { 1, 0xbef } },
+               { { ETH_HLEN, 0xbef } },
                .fill_helper = bpf_fill_ld_abs_vlan_push_pop,
        },
        /*
index 5e51872b3fc163af2fe82e6d7010b4aba08b612a..fbdf87920093b9b1dbd94e4b370a24e43d6bb8f7 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/module.h>
 
+/*
+ * Note: test functions are marked noinline so that their names appear in
+ * reports.
+ */
+
 static noinline void __init kmalloc_oob_right(void)
 {
        char *ptr;
@@ -411,6 +416,29 @@ static noinline void __init copy_user_test(void)
        kfree(kmem);
 }
 
+static noinline void __init use_after_scope_test(void)
+{
+       volatile char *volatile p;
+
+       pr_info("use-after-scope on int\n");
+       {
+               int local = 0;
+
+               p = (char *)&local;
+       }
+       p[0] = 1;
+       p[3] = 1;
+
+       pr_info("use-after-scope on array\n");
+       {
+               char local[1024] = {0};
+
+               p = local;
+       }
+       p[0] = 1;
+       p[1023] = 1;
+}
+
 static int __init kmalloc_tests_init(void)
 {
        kmalloc_oob_right();
@@ -436,6 +464,7 @@ static int __init kmalloc_tests_init(void)
        kasan_global_oob();
        ksize_unpoisons_memory();
        copy_user_test();
+       use_after_scope_test();
        return -EAGAIN;
 }
 
index be0ee11fa0d9ee8ff068244a559a2c52ad96c84c..86e3e0e74d20e78d173c1fa6dc4096f81695634e 100644 (file)
@@ -187,7 +187,7 @@ config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
        depends on SPARSEMEM || X86_64_ACPI_NUMA
        depends on ARCH_ENABLE_MEMORY_HOTPLUG
-       depends on !KASAN
+       depends on COMPILE_TEST || !KASAN
 
 config MEMORY_HOTPLUG_SPARSE
        def_bool y
index 384c2cb51b56bf75ab2c132d0087e3757a71c276..c960459eda7e640ea55be1d4ed80c6a9125a8877 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -385,6 +385,9 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align)
        bitmap_maxno = cma_bitmap_maxno(cma);
        bitmap_count = cma_bitmap_pages_to_bits(cma, count);
 
+       if (bitmap_count > bitmap_maxno)
+               return NULL;
+
        for (;;) {
                mutex_lock(&cma->lock);
                bitmap_no = bitmap_find_next_zero_area_off(cma->bitmap,
index 849f459ad0780e27bc256ff13fd52fa8c9007661..50b52fe51937ca70e62a33ab1553aef9b77ad1a0 100644 (file)
@@ -790,9 +790,7 @@ EXPORT_SYMBOL(__page_cache_alloc);
  */
 wait_queue_head_t *page_waitqueue(struct page *page)
 {
-       const struct zone *zone = page_zone(page);
-
-       return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
+       return bit_waitqueue(page, 0);
 }
 EXPORT_SYMBOL(page_waitqueue);
 
@@ -1734,6 +1732,9 @@ find_page:
                        if (inode->i_blkbits == PAGE_SHIFT ||
                                        !mapping->a_ops->is_partially_uptodate)
                                goto page_not_up_to_date;
+                       /* pipes can't handle partially uptodate pages */
+                       if (unlikely(iter->type & ITER_PIPE))
+                               goto page_not_up_to_date;
                        if (!trylock_page(page))
                                goto page_not_up_to_date;
                        /* Did it get truncated before we got the lock? */
index 381bb07ed14f2271e487fb98d0e95f6ff5470750..db77dcb38afda3d3720a228e14236fb2e324f929 100644 (file)
  * get_vaddr_frames() - map virtual addresses to pfns
  * @start:     starting user address
  * @nr_frames: number of pages / pfns from start to map
- * @write:     whether pages will be written to by the caller
- * @force:     whether to force write access even if user mapping is
- *             readonly. See description of the same argument of
-               get_user_pages().
+ * @gup_flags: flags modifying lookup behaviour
  * @vec:       structure which receives pages / pfns of the addresses mapped.
  *             It should have space for at least nr_frames entries.
  *
@@ -34,7 +31,7 @@
  * This function takes care of grabbing mmap_sem as necessary.
  */
 int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
-                    bool write, bool force, struct frame_vector *vec)
+                    unsigned int gup_flags, struct frame_vector *vec)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
@@ -59,7 +56,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
                vec->got_ref = true;
                vec->is_pfns = false;
                ret = get_user_pages_locked(start, nr_frames,
-                       write, force, (struct page **)(vec->ptrs), &locked);
+                       gup_flags, (struct page **)(vec->ptrs), &locked);
                goto out;
        }
 
index 96b2b2fd0fbd13f0b7385e7adc3359c6c7793503..ec4f82704b6f368bf4e128d3feb7356a8c482022 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -60,6 +60,16 @@ static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address,
        return -EEXIST;
 }
 
+/*
+ * FOLL_FORCE can write to even unwritable pte's, but only
+ * after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
+{
+       return pte_write(pte) ||
+               ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
+}
+
 static struct page *follow_page_pte(struct vm_area_struct *vma,
                unsigned long address, pmd_t *pmd, unsigned int flags)
 {
@@ -95,7 +105,7 @@ retry:
        }
        if ((flags & FOLL_NUMA) && pte_protnone(pte))
                goto no_page;
-       if ((flags & FOLL_WRITE) && !pte_write(pte)) {
+       if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
                pte_unmap_unlock(ptep, ptl);
                return NULL;
        }
@@ -412,7 +422,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
         * reCOWed by userspace write).
         */
        if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
-               *flags &= ~FOLL_WRITE;
+               *flags |= FOLL_COW;
        return 0;
 }
 
@@ -516,7 +526,7 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
  * instead of __get_user_pages. __get_user_pages should be used only if
  * you need some special @gup_flags.
  */
-long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                unsigned long start, unsigned long nr_pages,
                unsigned int gup_flags, struct page **pages,
                struct vm_area_struct **vmas, int *nonblocking)
@@ -621,7 +631,6 @@ next_page:
        } while (nr_pages);
        return i;
 }
-EXPORT_SYMBOL(__get_user_pages);
 
 bool vma_permits_fault(struct vm_area_struct *vma, unsigned int fault_flags)
 {
@@ -729,7 +738,6 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
                                                struct mm_struct *mm,
                                                unsigned long start,
                                                unsigned long nr_pages,
-                                               int write, int force,
                                                struct page **pages,
                                                struct vm_area_struct **vmas,
                                                int *locked, bool notify_drop,
@@ -747,10 +755,6 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
 
        if (pages)
                flags |= FOLL_GET;
-       if (write)
-               flags |= FOLL_WRITE;
-       if (force)
-               flags |= FOLL_FORCE;
 
        pages_done = 0;
        lock_dropped = false;
@@ -843,12 +847,12 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
  *          up_read(&mm->mmap_sem);
  */
 long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
-                          int write, int force, struct page **pages,
+                          unsigned int gup_flags, struct page **pages,
                           int *locked)
 {
        return __get_user_pages_locked(current, current->mm, start, nr_pages,
-                                      write, force, pages, NULL, locked, true,
-                                      FOLL_TOUCH);
+                                      pages, NULL, locked, true,
+                                      gup_flags | FOLL_TOUCH);
 }
 EXPORT_SYMBOL(get_user_pages_locked);
 
@@ -864,14 +868,14 @@ EXPORT_SYMBOL(get_user_pages_locked);
  */
 __always_inline long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
                                               unsigned long start, unsigned long nr_pages,
-                                              int write, int force, struct page **pages,
-                                              unsigned int gup_flags)
+                                              struct page **pages, unsigned int gup_flags)
 {
        long ret;
        int locked = 1;
+
        down_read(&mm->mmap_sem);
-       ret = __get_user_pages_locked(tsk, mm, start, nr_pages, write, force,
-                                     pages, NULL, &locked, false, gup_flags);
+       ret = __get_user_pages_locked(tsk, mm, start, nr_pages, pages, NULL,
+                                     &locked, false, gup_flags);
        if (locked)
                up_read(&mm->mmap_sem);
        return ret;
@@ -896,10 +900,10 @@ EXPORT_SYMBOL(__get_user_pages_unlocked);
  * "force" parameter).
  */
 long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
-                            int write, int force, struct page **pages)
+                            struct page **pages, unsigned int gup_flags)
 {
        return __get_user_pages_unlocked(current, current->mm, start, nr_pages,
-                                        write, force, pages, FOLL_TOUCH);
+                                        pages, gup_flags | FOLL_TOUCH);
 }
 EXPORT_SYMBOL(get_user_pages_unlocked);
 
@@ -910,9 +914,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
  * @mm:                mm_struct of target mm
  * @start:     starting user address
  * @nr_pages:  number of pages from start to pin
- * @write:     whether pages will be written to by the caller
- * @force:     whether to force access even when user mapping is currently
- *             protected (but never forces write access to shared mapping).
+ * @gup_flags: flags modifying lookup behaviour
  * @pages:     array that receives pointers to the pages pinned.
  *             Should be at least nr_pages long. Or NULL, if caller
  *             only intends to ensure the pages are faulted in.
@@ -941,9 +943,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
  * or similar operation cannot guarantee anything stronger anyway because
  * locks can't be held over the syscall boundary.
  *
- * If write=0, the page must not be written to. If the page is written to,
- * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
- * after the page is finished with, and before put_page is called.
+ * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
+ * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
+ * be called after the page is finished with, and before put_page is called.
  *
  * get_user_pages is typically used for fewer-copy IO operations, to get a
  * handle on the memory by some means other than accesses via the user virtual
@@ -960,12 +962,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
  */
 long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
                unsigned long start, unsigned long nr_pages,
-               int write, int force, struct page **pages,
+               unsigned int gup_flags, struct page **pages,
                struct vm_area_struct **vmas)
 {
-       return __get_user_pages_locked(tsk, mm, start, nr_pages, write, force,
-                                      pages, vmas, NULL, false,
-                                      FOLL_TOUCH | FOLL_REMOTE);
+       return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
+                                      NULL, false,
+                                      gup_flags | FOLL_TOUCH | FOLL_REMOTE);
 }
 EXPORT_SYMBOL(get_user_pages_remote);
 
@@ -976,12 +978,12 @@ EXPORT_SYMBOL(get_user_pages_remote);
  * obviously don't pass FOLL_REMOTE in here.
  */
 long get_user_pages(unsigned long start, unsigned long nr_pages,
-               int write, int force, struct page **pages,
+               unsigned int gup_flags, struct page **pages,
                struct vm_area_struct **vmas)
 {
        return __get_user_pages_locked(current, current->mm, start, nr_pages,
-                                      write, force, pages, vmas, NULL, false,
-                                      FOLL_TOUCH);
+                                      pages, vmas, NULL, false,
+                                      gup_flags | FOLL_TOUCH);
 }
 EXPORT_SYMBOL(get_user_pages);
 
@@ -1505,7 +1507,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                start += nr << PAGE_SHIFT;
                pages += nr;
 
-               ret = get_user_pages_unlocked(start, nr_pages - nr, write, 0, pages);
+               ret = get_user_pages_unlocked(start, nr_pages - nr, pages,
+                               write ? FOLL_WRITE : 0);
 
                /* Have to be a bit careful with return values */
                if (nr > 0) {
index cdcd25cb30fea3f2ad2c660e547d014b7378b3dd..d4a6e40015128c626f606e339474d8b23d90607e 100644 (file)
@@ -1426,11 +1426,12 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
 
 bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
                  unsigned long new_addr, unsigned long old_end,
-                 pmd_t *old_pmd, pmd_t *new_pmd)
+                 pmd_t *old_pmd, pmd_t *new_pmd, bool *need_flush)
 {
        spinlock_t *old_ptl, *new_ptl;
        pmd_t pmd;
        struct mm_struct *mm = vma->vm_mm;
+       bool force_flush = false;
 
        if ((old_addr & ~HPAGE_PMD_MASK) ||
            (new_addr & ~HPAGE_PMD_MASK) ||
@@ -1456,6 +1457,8 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
                if (new_ptl != old_ptl)
                        spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
                pmd = pmdp_huge_get_and_clear(mm, old_addr, old_pmd);
+               if (pmd_present(pmd) && pmd_dirty(pmd))
+                       force_flush = true;
                VM_BUG_ON(!pmd_none(*new_pmd));
 
                if (pmd_move_must_withdraw(new_ptl, old_ptl) &&
@@ -1467,6 +1470,10 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
                set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd));
                if (new_ptl != old_ptl)
                        spin_unlock(new_ptl);
+               if (force_flush)
+                       flush_tlb_range(vma, old_addr, old_addr + PMD_SIZE);
+               else
+                       *need_flush = true;
                spin_unlock(old_ptl);
                return true;
        }
index ec49d9ef1eefd0155f099d813ed547c16172d69e..418bf01a50ed1f9dde0ca6c083aafa86c1869f23 100644 (file)
@@ -1826,11 +1826,17 @@ static void return_unused_surplus_pages(struct hstate *h,
  * is not the case is if a reserve map was changed between calls.  It
  * is the responsibility of the caller to notice the difference and
  * take appropriate action.
+ *
+ * vma_add_reservation is used in error paths where a reservation must
+ * be restored when a newly allocated huge page must be freed.  It is
+ * to be called after calling vma_needs_reservation to determine if a
+ * reservation exists.
  */
 enum vma_resv_mode {
        VMA_NEEDS_RESV,
        VMA_COMMIT_RESV,
        VMA_END_RESV,
+       VMA_ADD_RESV,
 };
 static long __vma_reservation_common(struct hstate *h,
                                struct vm_area_struct *vma, unsigned long addr,
@@ -1856,6 +1862,14 @@ static long __vma_reservation_common(struct hstate *h,
                region_abort(resv, idx, idx + 1);
                ret = 0;
                break;
+       case VMA_ADD_RESV:
+               if (vma->vm_flags & VM_MAYSHARE)
+                       ret = region_add(resv, idx, idx + 1);
+               else {
+                       region_abort(resv, idx, idx + 1);
+                       ret = region_del(resv, idx, idx + 1);
+               }
+               break;
        default:
                BUG();
        }
@@ -1903,6 +1917,56 @@ static void vma_end_reservation(struct hstate *h,
        (void)__vma_reservation_common(h, vma, addr, VMA_END_RESV);
 }
 
+static long vma_add_reservation(struct hstate *h,
+                       struct vm_area_struct *vma, unsigned long addr)
+{
+       return __vma_reservation_common(h, vma, addr, VMA_ADD_RESV);
+}
+
+/*
+ * This routine is called to restore a reservation on error paths.  In the
+ * specific error paths, a huge page was allocated (via alloc_huge_page)
+ * and is about to be freed.  If a reservation for the page existed,
+ * alloc_huge_page would have consumed the reservation and set PagePrivate
+ * in the newly allocated page.  When the page is freed via free_huge_page,
+ * the global reservation count will be incremented if PagePrivate is set.
+ * However, free_huge_page can not adjust the reserve map.  Adjust the
+ * reserve map here to be consistent with global reserve count adjustments
+ * to be made by free_huge_page.
+ */
+static void restore_reserve_on_error(struct hstate *h,
+                       struct vm_area_struct *vma, unsigned long address,
+                       struct page *page)
+{
+       if (unlikely(PagePrivate(page))) {
+               long rc = vma_needs_reservation(h, vma, address);
+
+               if (unlikely(rc < 0)) {
+                       /*
+                        * Rare out of memory condition in reserve map
+                        * manipulation.  Clear PagePrivate so that
+                        * global reserve count will not be incremented
+                        * by free_huge_page.  This will make it appear
+                        * as though the reservation for this page was
+                        * consumed.  This may prevent the task from
+                        * faulting in the page at a later time.  This
+                        * is better than inconsistent global huge page
+                        * accounting of reserve counts.
+                        */
+                       ClearPagePrivate(page);
+               } else if (rc) {
+                       rc = vma_add_reservation(h, vma, address);
+                       if (unlikely(rc < 0))
+                               /*
+                                * See above comment about rare out of
+                                * memory condition.
+                                */
+                               ClearPagePrivate(page);
+               } else
+                       vma_end_reservation(h, vma, address);
+       }
+}
+
 struct page *alloc_huge_page(struct vm_area_struct *vma,
                                    unsigned long addr, int avoid_reserve)
 {
@@ -3498,6 +3562,7 @@ retry_avoidcopy:
        spin_unlock(ptl);
        mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
 out_release_all:
+       restore_reserve_on_error(h, vma, address, new_page);
        put_page(new_page);
 out_release_old:
        put_page(old_page);
@@ -3680,6 +3745,7 @@ backout:
        spin_unlock(ptl);
 backout_unlocked:
        unlock_page(page);
+       restore_reserve_on_error(h, vma, address, page);
        put_page(page);
        goto out;
 }
index 88af13c00d3cbfedb1d6d42ef5ddcf6ca9a50cab..0e9505f66ec133bd401d6ec9208d1a6f17b95fb7 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
+#include <linux/bug.h>
 
 #include "kasan.h"
 #include "../slab.h"
@@ -62,7 +63,7 @@ void kasan_unpoison_shadow(const void *address, size_t size)
        }
 }
 
-static void __kasan_unpoison_stack(struct task_struct *task, void *sp)
+static void __kasan_unpoison_stack(struct task_struct *task, const void *sp)
 {
        void *base = task_stack_page(task);
        size_t size = sp - base;
@@ -77,9 +78,24 @@ void kasan_unpoison_task_stack(struct task_struct *task)
 }
 
 /* Unpoison the stack for the current task beyond a watermark sp value. */
-asmlinkage void kasan_unpoison_remaining_stack(void *sp)
+asmlinkage void kasan_unpoison_task_stack_below(const void *watermark)
 {
-       __kasan_unpoison_stack(current, sp);
+       __kasan_unpoison_stack(current, watermark);
+}
+
+/*
+ * Clear all poison for the region between the current SP and a provided
+ * watermark value, as is sometimes required prior to hand-crafted asm function
+ * returns in the middle of functions.
+ */
+void kasan_unpoison_stack_above_sp_to(const void *watermark)
+{
+       const void *sp = __builtin_frame_address(0);
+       size_t size = watermark - sp;
+
+       if (WARN_ON(sp > watermark))
+               return;
+       kasan_unpoison_shadow(sp, size);
 }
 
 /*
@@ -748,6 +764,25 @@ EXPORT_SYMBOL(__asan_storeN_noabort);
 void __asan_handle_no_return(void) {}
 EXPORT_SYMBOL(__asan_handle_no_return);
 
+/* Emitted by compiler to poison large objects when they go out of scope. */
+void __asan_poison_stack_memory(const void *addr, size_t size)
+{
+       /*
+        * Addr is KASAN_SHADOW_SCALE_SIZE-aligned and the object is surrounded
+        * by redzones, so we simply round up size to simplify logic.
+        */
+       kasan_poison_shadow(addr, round_up(size, KASAN_SHADOW_SCALE_SIZE),
+                           KASAN_USE_AFTER_SCOPE);
+}
+EXPORT_SYMBOL(__asan_poison_stack_memory);
+
+/* Emitted by compiler to unpoison large objects when they go into scope. */
+void __asan_unpoison_stack_memory(const void *addr, size_t size)
+{
+       kasan_unpoison_shadow(addr, size);
+}
+EXPORT_SYMBOL(__asan_unpoison_stack_memory);
+
 #ifdef CONFIG_MEMORY_HOTPLUG
 static int kasan_mem_notifier(struct notifier_block *nb,
                        unsigned long action, void *data)
index e5c2181fee6f5ddeee0a6f912ba810637eeceb0c..1c260e6b3b3c6a1f26fc1e13a0fdb39099bbbf68 100644 (file)
@@ -21,6 +21,7 @@
 #define KASAN_STACK_MID         0xF2
 #define KASAN_STACK_RIGHT       0xF3
 #define KASAN_STACK_PARTIAL     0xF4
+#define KASAN_USE_AFTER_SCOPE   0xF8
 
 /* Don't break randconfig/all*config builds */
 #ifndef KASAN_ABI_VERSION
@@ -53,6 +54,9 @@ struct kasan_global {
 #if KASAN_ABI_VERSION >= 4
        struct kasan_source_location *location;
 #endif
+#if KASAN_ABI_VERSION >= 5
+       char *odr_indicator;
+#endif
 };
 
 /**
index 24c1211fe9d5e16afa715fb0b69f4aee96424224..073325aedc68542a3b05f3859d89a9872aef815f 100644 (file)
@@ -90,6 +90,9 @@ static void print_error_description(struct kasan_access_info *info)
        case KASAN_KMALLOC_FREE:
                bug_type = "use-after-free";
                break;
+       case KASAN_USE_AFTER_SCOPE:
+               bug_type = "use-after-scope";
+               break;
        }
 
        pr_err("BUG: KASAN: %s in %pS at addr %p\n",
index 728d7790dc2da27175d403f314a359cec70da5fc..87e1a7ca38463d0809e54ca8c74d4e2b0eb415eb 100644 (file)
@@ -103,6 +103,7 @@ static struct khugepaged_scan khugepaged_scan = {
        .mm_head = LIST_HEAD_INIT(khugepaged_scan.mm_head),
 };
 
+#ifdef CONFIG_SYSFS
 static ssize_t scan_sleep_millisecs_show(struct kobject *kobj,
                                         struct kobj_attribute *attr,
                                         char *buf)
@@ -295,6 +296,7 @@ struct attribute_group khugepaged_attr_group = {
        .attrs = khugepaged_attr,
        .name = "khugepaged",
 };
+#endif /* CONFIG_SYSFS */
 
 #define VM_NO_KHUGEPAGED (VM_SPECIAL | VM_HUGETLB)
 
index a5e453cf05c499cf5c7eeb9b66ce14936d4494fd..d1380ed93fdf084d5043a2fb1f8bb3e476cb7bf9 100644 (file)
@@ -1414,6 +1414,7 @@ static void kmemleak_scan(void)
        /* data/bss scanning */
        scan_large_block(_sdata, _edata);
        scan_large_block(__bss_start, __bss_stop);
+       scan_large_block(__start_data_ro_after_init, __end_data_ro_after_init);
 
 #ifdef CONFIG_SMP
        /* per-cpu sections scanning */
@@ -1453,8 +1454,11 @@ static void kmemleak_scan(void)
 
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
-                       scan_block(task_stack_page(p), task_stack_page(p) +
-                                  THREAD_SIZE, NULL);
+                       void *stack = try_get_task_stack(p);
+                       if (stack) {
+                               scan_block(stack, stack + THREAD_SIZE, NULL);
+                               put_task_stack(p);
+                       }
                } while_each_thread(g, p);
                read_unlock(&tasklist_lock);
        }
index 1d05cb9d363d0bfadd6a9c58efccd0551d0bd7f2..234676e31edd3b0609014a3adcf4fb4e200a0c0e 100644 (file)
@@ -554,6 +554,8 @@ int __list_lru_init(struct list_lru *lru, bool memcg_aware,
        err = memcg_init_list_lru(lru, memcg_aware);
        if (err) {
                kfree(lru->node);
+               /* Do this so a list_lru_destroy() doesn't crash: */
+               lru->node = NULL;
                goto out;
        }
 
index ae052b5e3315217874569d0c1cf57ade9cea99a1..0f870ba43942e74d1d535a13437e446da5863b1a 100644 (file)
@@ -1917,6 +1917,15 @@ retry:
                     current->flags & PF_EXITING))
                goto force;
 
+       /*
+        * Prevent unbounded recursion when reclaim operations need to
+        * allocate memory. This might exceed the limits temporarily,
+        * but we prefer facilitating memory reclaim and getting back
+        * under the limit over triggering OOM kills in these cases.
+        */
+       if (unlikely(current->flags & PF_MEMALLOC))
+               goto force;
+
        if (unlikely(task_in_memcg_oom(current)))
                goto nomem;
 
index de88f33519c0d6398de8fcc06bfa82f2a477dd95..19e796d36a629147dd36217ecab34934300dc660 100644 (file)
@@ -1112,10 +1112,10 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        }
 
        if (!PageHuge(p) && PageTransHuge(hpage)) {
-               lock_page(hpage);
-               if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
-                       unlock_page(hpage);
-                       if (!PageAnon(hpage))
+               lock_page(p);
+               if (!PageAnon(p) || unlikely(split_huge_page(p))) {
+                       unlock_page(p);
+                       if (!PageAnon(p))
                                pr_err("Memory failure: %#lx: non anonymous thp\n",
                                        pfn);
                        else
@@ -1126,9 +1126,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
                        put_hwpoison_page(p);
                        return -EBUSY;
                }
-               unlock_page(hpage);
-               get_hwpoison_page(p);
-               put_hwpoison_page(hpage);
+               unlock_page(p);
                VM_BUG_ON_PAGE(!page_count(p), p);
                hpage = compound_head(p);
        }
index fc1987dfd8cc7f62fa911fd905f743cb3ec53ec3..e18c57bdc75c4c96e3ef79546afe11fab5a3c07a 100644 (file)
@@ -3869,10 +3869,11 @@ EXPORT_SYMBOL_GPL(generic_access_phys);
  * given task for page fault accounting.
  */
 static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long addr, void *buf, int len, int write)
+               unsigned long addr, void *buf, int len, unsigned int gup_flags)
 {
        struct vm_area_struct *vma;
        void *old_buf = buf;
+       int write = gup_flags & FOLL_WRITE;
 
        down_read(&mm->mmap_sem);
        /* ignore errors, just check how much was successfully transferred */
@@ -3882,7 +3883,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
                struct page *page = NULL;
 
                ret = get_user_pages_remote(tsk, mm, addr, 1,
-                               write, 1, &page, &vma);
+                               gup_flags, &page, &vma);
                if (ret <= 0) {
 #ifndef CONFIG_HAVE_IOREMAP_PROT
                        break;
@@ -3934,14 +3935,14 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
  * @addr:      start address to access
  * @buf:       source or destination buffer
  * @len:       number of bytes to transfer
- * @write:     whether the access is a write
+ * @gup_flags: flags modifying lookup behaviour
  *
  * The caller must hold a reference on @mm.
  */
 int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-               void *buf, int len, int write)
+               void *buf, int len, unsigned int gup_flags)
 {
-       return __access_remote_vm(NULL, mm, addr, buf, len, write);
+       return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags);
 }
 
 /*
@@ -3950,7 +3951,7 @@ int access_remote_vm(struct mm_struct *mm, unsigned long addr,
  * Do not walk the page table directly, use get_user_pages
  */
 int access_process_vm(struct task_struct *tsk, unsigned long addr,
-               void *buf, int len, int write)
+               void *buf, int len, unsigned int gup_flags)
 {
        struct mm_struct *mm;
        int ret;
@@ -3959,7 +3960,8 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr,
        if (!mm)
                return 0;
 
-       ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
+       ret = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags);
+
        mmput(mm);
 
        return ret;
index 962927309b6e963fa05a0acf09608c2ec6cef761..cad4b9125695cfbfcc7509e942f6d8f8a37f460c 100644 (file)
@@ -268,7 +268,6 @@ void __init register_page_bootmem_info_node(struct pglist_data *pgdat)
        unsigned long i, pfn, end_pfn, nr_pages;
        int node = pgdat->node_id;
        struct page *page;
-       struct zone *zone;
 
        nr_pages = PAGE_ALIGN(sizeof(struct pglist_data)) >> PAGE_SHIFT;
        page = virt_to_page(pgdat);
@@ -276,19 +275,6 @@ void __init register_page_bootmem_info_node(struct pglist_data *pgdat)
        for (i = 0; i < nr_pages; i++, page++)
                get_page_bootmem(node, page, NODE_INFO);
 
-       zone = &pgdat->node_zones[0];
-       for (; zone < pgdat->node_zones + MAX_NR_ZONES - 1; zone++) {
-               if (zone_is_initialized(zone)) {
-                       nr_pages = zone->wait_table_hash_nr_entries
-                               * sizeof(wait_queue_head_t);
-                       nr_pages = PAGE_ALIGN(nr_pages) >> PAGE_SHIFT;
-                       page = virt_to_page(zone->wait_table);
-
-                       for (i = 0; i < nr_pages; i++, page++)
-                               get_page_bootmem(node, page, NODE_INFO);
-               }
-       }
-
        pfn = pgdat->node_start_pfn;
        end_pfn = pgdat_end_pfn(pgdat);
 
@@ -2131,7 +2117,6 @@ void try_offline_node(int nid)
        unsigned long start_pfn = pgdat->node_start_pfn;
        unsigned long end_pfn = start_pfn + pgdat->node_spanned_pages;
        unsigned long pfn;
-       int i;
 
        for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
                unsigned long section_nr = pfn_to_section_nr(pfn);
@@ -2158,20 +2143,6 @@ void try_offline_node(int nid)
         */
        node_set_offline(nid);
        unregister_one_node(nid);
-
-       /* free waittable in each zone */
-       for (i = 0; i < MAX_NR_ZONES; i++) {
-               struct zone *zone = pgdat->node_zones + i;
-
-               /*
-                * wait_table may be allocated from boot memory,
-                * here only free if it's allocated by vmalloc.
-                */
-               if (is_vmalloc_addr(zone->wait_table)) {
-                       vfree(zone->wait_table);
-                       zone->wait_table = NULL;
-               }
-       }
 }
 EXPORT_SYMBOL(try_offline_node);
 
index ad1c96ac313c0f442b1635baaa96555d355a74bb..0b859af06b87df4e17af4180b953a6337c251dff 100644 (file)
@@ -850,7 +850,7 @@ static int lookup_node(unsigned long addr)
        struct page *p;
        int err;
 
-       err = get_user_pages(addr & PAGE_MASK, 1, 0, 0, &p, NULL);
+       err = get_user_pages(addr & PAGE_MASK, 1, 0, &p, NULL);
        if (err >= 0) {
                err = page_to_nid(p);
                put_page(p);
index 145a4258ddbc775d1d2acf133a21b83280a8f282..cdbed8aaa4268c94abb44a8adf6c93873d37856a 100644 (file)
@@ -190,10 +190,13 @@ unsigned int munlock_vma_page(struct page *page)
         */
        spin_lock_irq(zone_lru_lock(zone));
 
-       nr_pages = hpage_nr_pages(page);
-       if (!TestClearPageMlocked(page))
+       if (!TestClearPageMlocked(page)) {
+               /* Potentially, PTE-mapped THP: do not skip the rest PTEs */
+               nr_pages = 1;
                goto unlock_out;
+       }
 
+       nr_pages = hpage_nr_pages(page);
        __mod_zone_page_state(zone, NR_MLOCK, -nr_pages);
 
        if (__munlock_isolate_lru_page(page, true)) {
index bcdbe62f3e6da12766f0d96a24aa4c2111614e6b..11936526b08b8c5f5c5d0454f6789008a0c6f313 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/perf_event.h>
 #include <linux/pkeys.h>
 #include <linux/ksm.h>
-#include <linux/pkeys.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
index da22ad2a5678265ea9f2d0aa5ece9e14c519a494..30d7d2482eea1d04cf72b03bcd54d1d293f666e4 100644 (file)
@@ -104,11 +104,13 @@ static pte_t move_soft_dirty_pte(pte_t pte)
 static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                unsigned long old_addr, unsigned long old_end,
                struct vm_area_struct *new_vma, pmd_t *new_pmd,
-               unsigned long new_addr, bool need_rmap_locks)
+               unsigned long new_addr, bool need_rmap_locks, bool *need_flush)
 {
        struct mm_struct *mm = vma->vm_mm;
        pte_t *old_pte, *new_pte, pte;
        spinlock_t *old_ptl, *new_ptl;
+       bool force_flush = false;
+       unsigned long len = old_end - old_addr;
 
        /*
         * When need_rmap_locks is true, we take the i_mmap_rwsem and anon_vma
@@ -146,7 +148,19 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                                   new_pte++, new_addr += PAGE_SIZE) {
                if (pte_none(*old_pte))
                        continue;
+
                pte = ptep_get_and_clear(mm, old_addr, old_pte);
+               /*
+                * If we are remapping a dirty PTE, make sure
+                * to flush TLB before we drop the PTL for the
+                * old PTE or we may race with page_mkclean().
+                *
+                * This check has to be done after we removed the
+                * old PTE from page tables or another thread may
+                * dirty it after the check and before the removal.
+                */
+               if (pte_present(pte) && pte_dirty(pte))
+                       force_flush = true;
                pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr);
                pte = move_soft_dirty_pte(pte);
                set_pte_at(mm, new_addr, new_pte, pte);
@@ -156,6 +170,10 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
        if (new_ptl != old_ptl)
                spin_unlock(new_ptl);
        pte_unmap(new_pte - 1);
+       if (force_flush)
+               flush_tlb_range(vma, old_end - len, old_end);
+       else
+               *need_flush = true;
        pte_unmap_unlock(old_pte - 1, old_ptl);
        if (need_rmap_locks)
                drop_rmap_locks(vma);
@@ -201,13 +219,12 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
                                if (need_rmap_locks)
                                        take_rmap_locks(vma);
                                moved = move_huge_pmd(vma, old_addr, new_addr,
-                                                   old_end, old_pmd, new_pmd);
+                                                   old_end, old_pmd, new_pmd,
+                                                   &need_flush);
                                if (need_rmap_locks)
                                        drop_rmap_locks(vma);
-                               if (moved) {
-                                       need_flush = true;
+                               if (moved)
                                        continue;
-                               }
                        }
                        split_huge_pmd(vma, old_pmd, old_addr);
                        if (pmd_trans_unstable(old_pmd))
@@ -220,11 +237,10 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
                        extent = next - new_addr;
                if (extent > LATENCY_LIMIT)
                        extent = LATENCY_LIMIT;
-               move_ptes(vma, old_pmd, old_addr, old_addr + extent,
-                         new_vma, new_pmd, new_addr, need_rmap_locks);
-               need_flush = true;
+               move_ptes(vma, old_pmd, old_addr, old_addr + extent, new_vma,
+                         new_pmd, new_addr, need_rmap_locks, &need_flush);
        }
-       if (likely(need_flush))
+       if (need_flush)
                flush_tlb_range(vma, old_end-len, old_addr);
 
        mmu_notifier_invalidate_range_end(vma->vm_mm, mmun_start, mmun_end);
index 95daf81a4855d99d2ae176ab16c92a1b4302b0ae..8b8faaf2a9e95cfc607ff1a5a37c83eadfda59fe 100644 (file)
@@ -109,7 +109,7 @@ unsigned int kobjsize(const void *objp)
        return PAGE_SIZE << compound_order(page);
 }
 
-long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                      unsigned long start, unsigned long nr_pages,
                      unsigned int foll_flags, struct page **pages,
                      struct vm_area_struct **vmas, int *nonblocking)
@@ -160,33 +160,25 @@ finish_or_fault:
  * - don't permit access to VMAs that don't support it, such as I/O mappings
  */
 long get_user_pages(unsigned long start, unsigned long nr_pages,
-                   int write, int force, struct page **pages,
+                   unsigned int gup_flags, struct page **pages,
                    struct vm_area_struct **vmas)
 {
-       int flags = 0;
-
-       if (write)
-               flags |= FOLL_WRITE;
-       if (force)
-               flags |= FOLL_FORCE;
-
-       return __get_user_pages(current, current->mm, start, nr_pages, flags,
-                               pages, vmas, NULL);
+       return __get_user_pages(current, current->mm, start, nr_pages,
+                               gup_flags, pages, vmas, NULL);
 }
 EXPORT_SYMBOL(get_user_pages);
 
 long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
-                           int write, int force, struct page **pages,
+                           unsigned int gup_flags, struct page **pages,
                            int *locked)
 {
-       return get_user_pages(start, nr_pages, write, force, pages, NULL);
+       return get_user_pages(start, nr_pages, gup_flags, pages, NULL);
 }
 EXPORT_SYMBOL(get_user_pages_locked);
 
 long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
                               unsigned long start, unsigned long nr_pages,
-                              int write, int force, struct page **pages,
-                              unsigned int gup_flags)
+                              struct page **pages, unsigned int gup_flags)
 {
        long ret;
        down_read(&mm->mmap_sem);
@@ -198,10 +190,10 @@ long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm,
 EXPORT_SYMBOL(__get_user_pages_unlocked);
 
 long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
-                            int write, int force, struct page **pages)
+                            struct page **pages, unsigned int gup_flags)
 {
        return __get_user_pages_unlocked(current, current->mm, start, nr_pages,
-                                        write, force, pages, 0);
+                                        pages, gup_flags);
 }
 EXPORT_SYMBOL(get_user_pages_unlocked);
 
@@ -1817,9 +1809,10 @@ void filemap_map_pages(struct fault_env *fe,
 EXPORT_SYMBOL(filemap_map_pages);
 
 static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long addr, void *buf, int len, int write)
+               unsigned long addr, void *buf, int len, unsigned int gup_flags)
 {
        struct vm_area_struct *vma;
+       int write = gup_flags & FOLL_WRITE;
 
        down_read(&mm->mmap_sem);
 
@@ -1854,21 +1847,22 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
  * @addr:      start address to access
  * @buf:       source or destination buffer
  * @len:       number of bytes to transfer
- * @write:     whether the access is a write
+ * @gup_flags: flags modifying lookup behaviour
  *
  * The caller must hold a reference on @mm.
  */
 int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-               void *buf, int len, int write)
+               void *buf, int len, unsigned int gup_flags)
 {
-       return __access_remote_vm(NULL, mm, addr, buf, len, write);
+       return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags);
 }
 
 /*
  * Access another process' address space.
  * - source/target buffer must be kernel space
  */
-int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len,
+               unsigned int gup_flags)
 {
        struct mm_struct *mm;
 
@@ -1879,7 +1873,7 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
        if (!mm)
                return 0;
 
-       len = __access_remote_vm(tsk, mm, addr, buf, len, write);
+       len = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags);
 
        mmput(mm);
        return len;
index 2b3bf6767d5441a876890dce16d9de2d60f1e2bc..6de9440e3ae2d995b28577dc4a000fc23f4182c0 100644 (file)
@@ -92,7 +92,7 @@ int _node_numa_mem_[MAX_NUMNODES];
 #endif
 
 #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
-volatile u64 latent_entropy __latent_entropy;
+volatile unsigned long latent_entropy __latent_entropy;
 EXPORT_SYMBOL(latent_entropy);
 #endif
 
@@ -3658,7 +3658,7 @@ retry:
        /* Make sure we know about allocations which stall for too long */
        if (time_after(jiffies, alloc_start + stall_timeout)) {
                warn_alloc(gfp_mask,
-                       "page alloction stalls for %ums, order:%u\n",
+                       "page allocation stalls for %ums, order:%u",
                        jiffies_to_msecs(jiffies-alloc_start), order);
                stall_timeout += 10 * HZ;
        }
@@ -4224,7 +4224,7 @@ static void show_migration_types(unsigned char type)
        }
 
        *p = '\0';
-       printk("(%s) ", tmp);
+       printk(KERN_CONT "(%s) ", tmp);
 }
 
 /*
@@ -4335,7 +4335,8 @@ void show_free_areas(unsigned int filter)
                        free_pcp += per_cpu_ptr(zone->pageset, cpu)->pcp.count;
 
                show_node(zone);
-               printk("%s"
+               printk(KERN_CONT
+                       "%s"
                        " free:%lukB"
                        " min:%lukB"
                        " low:%lukB"
@@ -4382,8 +4383,8 @@ void show_free_areas(unsigned int filter)
                        K(zone_page_state(zone, NR_FREE_CMA_PAGES)));
                printk("lowmem_reserve[]:");
                for (i = 0; i < MAX_NR_ZONES; i++)
-                       printk(" %ld", zone->lowmem_reserve[i]);
-               printk("\n");
+                       printk(KERN_CONT " %ld", zone->lowmem_reserve[i]);
+               printk(KERN_CONT "\n");
        }
 
        for_each_populated_zone(zone) {
@@ -4394,7 +4395,7 @@ void show_free_areas(unsigned int filter)
                if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
-               printk("%s: ", zone->name);
+               printk(KERN_CONT "%s: ", zone->name);
 
                spin_lock_irqsave(&zone->lock, flags);
                for (order = 0; order < MAX_ORDER; order++) {
@@ -4412,11 +4413,12 @@ void show_free_areas(unsigned int filter)
                }
                spin_unlock_irqrestore(&zone->lock, flags);
                for (order = 0; order < MAX_ORDER; order++) {
-                       printk("%lu*%lukB ", nr[order], K(1UL) << order);
+                       printk(KERN_CONT "%lu*%lukB ",
+                              nr[order], K(1UL) << order);
                        if (nr[order])
                                show_migration_types(types[order]);
                }
-               printk("= %lukB\n", K(total));
+               printk(KERN_CONT "= %lukB\n", K(total));
        }
 
        hugetlb_show_meminfo();
@@ -4976,72 +4978,6 @@ void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone)
 #endif
 }
 
-/*
- * Helper functions to size the waitqueue hash table.
- * Essentially these want to choose hash table sizes sufficiently
- * large so that collisions trying to wait on pages are rare.
- * But in fact, the number of active page waitqueues on typical
- * systems is ridiculously low, less than 200. So this is even
- * conservative, even though it seems large.
- *
- * The constant PAGES_PER_WAITQUEUE specifies the ratio of pages to
- * waitqueues, i.e. the size of the waitq table given the number of pages.
- */
-#define PAGES_PER_WAITQUEUE    256
-
-#ifndef CONFIG_MEMORY_HOTPLUG
-static inline unsigned long wait_table_hash_nr_entries(unsigned long pages)
-{
-       unsigned long size = 1;
-
-       pages /= PAGES_PER_WAITQUEUE;
-
-       while (size < pages)
-               size <<= 1;
-
-       /*
-        * Once we have dozens or even hundreds of threads sleeping
-        * on IO we've got bigger problems than wait queue collision.
-        * Limit the size of the wait table to a reasonable size.
-        */
-       size = min(size, 4096UL);
-
-       return max(size, 4UL);
-}
-#else
-/*
- * A zone's size might be changed by hot-add, so it is not possible to determine
- * a suitable size for its wait_table.  So we use the maximum size now.
- *
- * The max wait table size = 4096 x sizeof(wait_queue_head_t).   ie:
- *
- *    i386 (preemption config)    : 4096 x 16 = 64Kbyte.
- *    ia64, x86-64 (no preemption): 4096 x 20 = 80Kbyte.
- *    ia64, x86-64 (preemption)   : 4096 x 24 = 96Kbyte.
- *
- * The maximum entries are prepared when a zone's memory is (512K + 256) pages
- * or more by the traditional way. (See above).  It equals:
- *
- *    i386, x86-64, powerpc(4K page size) : =  ( 2G + 1M)byte.
- *    ia64(16K page size)                 : =  ( 8G + 4M)byte.
- *    powerpc (64K page size)             : =  (32G +16M)byte.
- */
-static inline unsigned long wait_table_hash_nr_entries(unsigned long pages)
-{
-       return 4096UL;
-}
-#endif
-
-/*
- * This is an integer logarithm so that shifts can be used later
- * to extract the more random high bits from the multiplicative
- * hash function before the remainder is taken.
- */
-static inline unsigned long wait_table_bits(unsigned long size)
-{
-       return ffz(~size);
-}
-
 /*
  * Initially all pages are reserved - free ones are freed
  * up by free_all_bootmem() once the early boot process is
@@ -5304,49 +5240,6 @@ void __init setup_per_cpu_pageset(void)
                        alloc_percpu(struct per_cpu_nodestat);
 }
 
-static noinline __ref
-int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
-{
-       int i;
-       size_t alloc_size;
-
-       /*
-        * The per-page waitqueue mechanism uses hashed waitqueues
-        * per zone.
-        */
-       zone->wait_table_hash_nr_entries =
-                wait_table_hash_nr_entries(zone_size_pages);
-       zone->wait_table_bits =
-               wait_table_bits(zone->wait_table_hash_nr_entries);
-       alloc_size = zone->wait_table_hash_nr_entries
-                                       * sizeof(wait_queue_head_t);
-
-       if (!slab_is_available()) {
-               zone->wait_table = (wait_queue_head_t *)
-                       memblock_virt_alloc_node_nopanic(
-                               alloc_size, zone->zone_pgdat->node_id);
-       } else {
-               /*
-                * This case means that a zone whose size was 0 gets new memory
-                * via memory hot-add.
-                * But it may be the case that a new node was hot-added.  In
-                * this case vmalloc() will not be able to use this new node's
-                * memory - this wait_table must be initialized to use this new
-                * node itself as well.
-                * To use this new node's memory, further consideration will be
-                * necessary.
-                */
-               zone->wait_table = vmalloc(alloc_size);
-       }
-       if (!zone->wait_table)
-               return -ENOMEM;
-
-       for (i = 0; i < zone->wait_table_hash_nr_entries; ++i)
-               init_waitqueue_head(zone->wait_table + i);
-
-       return 0;
-}
-
 static __meminit void zone_pcp_init(struct zone *zone)
 {
        /*
@@ -5367,10 +5260,7 @@ int __meminit init_currently_empty_zone(struct zone *zone,
                                        unsigned long size)
 {
        struct pglist_data *pgdat = zone->zone_pgdat;
-       int ret;
-       ret = zone_wait_table_init(zone, size);
-       if (ret)
-               return ret;
+
        pgdat->nr_zones = zone_idx(zone) + 1;
 
        zone->zone_start_pfn = zone_start_pfn;
@@ -5382,6 +5272,7 @@ int __meminit init_currently_empty_zone(struct zone *zone,
                        zone_start_pfn, (zone_start_pfn + size));
 
        zone_init_free_lists(zone);
+       zone->initialized = 1;
 
        return 0;
 }
index 07514d41ebcc1623b789fc93e09794058ecdc6ca..be8dc8d1edb95b34d8c6b7fbf34321e597e981e1 100644 (file)
@@ -88,12 +88,16 @@ static int process_vm_rw_single_vec(unsigned long addr,
        ssize_t rc = 0;
        unsigned long max_pages_per_loop = PVM_MAX_KMALLOC_PAGES
                / sizeof(struct pages *);
+       unsigned int flags = FOLL_REMOTE;
 
        /* Work out address and page range required */
        if (len == 0)
                return 0;
        nr_pages = (addr + len - 1) / PAGE_SIZE - addr / PAGE_SIZE + 1;
 
+       if (vm_write)
+               flags |= FOLL_WRITE;
+
        while (!rc && nr_pages && iov_iter_count(iter)) {
                int pages = min(nr_pages, max_pages_per_loop);
                size_t bytes;
@@ -104,8 +108,7 @@ static int process_vm_rw_single_vec(unsigned long addr,
                 * current/current->mm
                 */
                pages = __get_user_pages_unlocked(task, mm, pa, pages,
-                                                 vm_write, 0, process_pages,
-                                                 FOLL_REMOTE);
+                                                 process_pages, flags);
                if (pages <= 0)
                        return -EFAULT;
 
index ad7813d73ea79879008eb570e790a101a4d7c3f7..9d32e1cb9f38f7dd508f1be0273d0721974b2c05 100644 (file)
@@ -1483,6 +1483,8 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp,
        copy_highpage(newpage, oldpage);
        flush_dcache_page(newpage);
 
+       __SetPageLocked(newpage);
+       __SetPageSwapBacked(newpage);
        SetPageUptodate(newpage);
        set_page_private(newpage, swap_index);
        SetPageSwapCache(newpage);
@@ -1846,6 +1848,18 @@ unlock:
        return error;
 }
 
+/*
+ * This is like autoremove_wake_function, but it removes the wait queue
+ * entry unconditionally - even if something else had already woken the
+ * target.
+ */
+static int synchronous_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+       int ret = default_wake_function(wait, mode, sync, key);
+       list_del_init(&wait->task_list);
+       return ret;
+}
+
 static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct inode *inode = file_inode(vma->vm_file);
@@ -1881,7 +1895,7 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                    vmf->pgoff >= shmem_falloc->start &&
                    vmf->pgoff < shmem_falloc->next) {
                        wait_queue_head_t *shmem_falloc_waitq;
-                       DEFINE_WAIT(shmem_fault_wait);
+                       DEFINE_WAIT_FUNC(shmem_fault_wait, synchronous_wake_function);
 
                        ret = VM_FAULT_NOPAGE;
                        if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) &&
@@ -2663,6 +2677,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
                spin_lock(&inode->i_lock);
                inode->i_private = NULL;
                wake_up_all(&shmem_falloc_waitq);
+               WARN_ON_ONCE(!list_empty(&shmem_falloc_waitq.task_list));
                spin_unlock(&inode->i_lock);
                error = 0;
                goto out;
index 090fb26b3a39b4feba105650f2a663f5c9972064..0b0550ca85b40c9108b4085873d67babc200885d 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -233,6 +233,7 @@ static void kmem_cache_node_init(struct kmem_cache_node *parent)
        spin_lock_init(&parent->list_lock);
        parent->free_objects = 0;
        parent->free_touched = 0;
+       parent->num_slabs = 0;
 }
 
 #define MAKE_LIST(cachep, listp, slab, nodeid)                         \
@@ -966,7 +967,7 @@ static int setup_kmem_cache_node(struct kmem_cache *cachep,
         * guaranteed to be valid until irq is re-enabled, because it will be
         * freed after synchronize_sched().
         */
-       if (force_change)
+       if (old_shared && force_change)
                synchronize_sched();
 
 fail:
@@ -1382,24 +1383,27 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
        for_each_kmem_cache_node(cachep, node, n) {
                unsigned long active_objs = 0, num_objs = 0, free_objects = 0;
                unsigned long active_slabs = 0, num_slabs = 0;
+               unsigned long num_slabs_partial = 0, num_slabs_free = 0;
+               unsigned long num_slabs_full;
 
                spin_lock_irqsave(&n->list_lock, flags);
-               list_for_each_entry(page, &n->slabs_full, lru) {
-                       active_objs += cachep->num;
-                       active_slabs++;
-               }
+               num_slabs = n->num_slabs;
                list_for_each_entry(page, &n->slabs_partial, lru) {
                        active_objs += page->active;
-                       active_slabs++;
+                       num_slabs_partial++;
                }
                list_for_each_entry(page, &n->slabs_free, lru)
-                       num_slabs++;
+                       num_slabs_free++;
 
                free_objects += n->free_objects;
                spin_unlock_irqrestore(&n->list_lock, flags);
 
-               num_slabs += active_slabs;
                num_objs = num_slabs * cachep->num;
+               active_slabs = num_slabs - num_slabs_free;
+               num_slabs_full = num_slabs -
+                       (num_slabs_partial + num_slabs_free);
+               active_objs += (num_slabs_full * cachep->num);
+
                pr_warn("  node %d: slabs: %ld/%ld, objs: %ld/%ld, free: %ld\n",
                        node, active_slabs, num_slabs, active_objs, num_objs,
                        free_objects);
@@ -2314,6 +2318,7 @@ static int drain_freelist(struct kmem_cache *cache,
 
                page = list_entry(p, struct page, lru);
                list_del(&page->lru);
+               n->num_slabs--;
                /*
                 * Safe to drop the lock. The slab is no longer linked
                 * to the cache.
@@ -2752,6 +2757,8 @@ static void cache_grow_end(struct kmem_cache *cachep, struct page *page)
                list_add_tail(&page->lru, &(n->slabs_free));
        else
                fixup_slab_list(cachep, n, page, &list);
+
+       n->num_slabs++;
        STATS_INC_GROWN(cachep);
        n->free_objects += cachep->num - page->active;
        spin_unlock(&n->list_lock);
@@ -3443,6 +3450,7 @@ static void free_block(struct kmem_cache *cachep, void **objpp,
 
                page = list_last_entry(&n->slabs_free, struct page, lru);
                list_move(&page->lru, list);
+               n->num_slabs--;
        }
 }
 
@@ -4099,6 +4107,8 @@ void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo)
        unsigned long num_objs;
        unsigned long active_slabs = 0;
        unsigned long num_slabs, free_objects = 0, shared_avail = 0;
+       unsigned long num_slabs_partial = 0, num_slabs_free = 0;
+       unsigned long num_slabs_full = 0;
        const char *name;
        char *error = NULL;
        int node;
@@ -4111,33 +4121,34 @@ void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo)
                check_irq_on();
                spin_lock_irq(&n->list_lock);
 
-               list_for_each_entry(page, &n->slabs_full, lru) {
-                       if (page->active != cachep->num && !error)
-                               error = "slabs_full accounting error";
-                       active_objs += cachep->num;
-                       active_slabs++;
-               }
+               num_slabs += n->num_slabs;
+
                list_for_each_entry(page, &n->slabs_partial, lru) {
                        if (page->active == cachep->num && !error)
                                error = "slabs_partial accounting error";
                        if (!page->active && !error)
                                error = "slabs_partial accounting error";
                        active_objs += page->active;
-                       active_slabs++;
+                       num_slabs_partial++;
                }
+
                list_for_each_entry(page, &n->slabs_free, lru) {
                        if (page->active && !error)
                                error = "slabs_free accounting error";
-                       num_slabs++;
+                       num_slabs_free++;
                }
+
                free_objects += n->free_objects;
                if (n->shared)
                        shared_avail += n->shared->avail;
 
                spin_unlock_irq(&n->list_lock);
        }
-       num_slabs += active_slabs;
        num_objs = num_slabs * cachep->num;
+       active_slabs = num_slabs - num_slabs_free;
+       num_slabs_full = num_slabs - (num_slabs_partial + num_slabs_free);
+       active_objs += (num_slabs_full * cachep->num);
+
        if (num_objs - active_objs != free_objects && !error)
                error = "free_objects accounting error";
 
index 9653f2e2591ad0982d2dc74c668323a43e5b026d..bc05fdc3edce106b12e5113ad8c8777de6de217d 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -432,6 +432,7 @@ struct kmem_cache_node {
        struct list_head slabs_partial; /* partial list first, better asm code */
        struct list_head slabs_full;
        struct list_head slabs_free;
+       unsigned long num_slabs;
        unsigned long free_objects;
        unsigned int free_limit;
        unsigned int colour_next;       /* Per-node cache coloring */
index 71f0b28a1bec8bc58a479f7c53343b647bcf5f24..329b03843863940f2288ea046d6b950d126c0a49 100644 (file)
@@ -533,8 +533,8 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg,
 
        s = create_cache(cache_name, root_cache->object_size,
                         root_cache->size, root_cache->align,
-                        root_cache->flags, root_cache->ctor,
-                        memcg, root_cache);
+                        root_cache->flags & CACHE_CREATE_MASK,
+                        root_cache->ctor, memcg, root_cache);
        /*
         * If we could not create a memcg cache, do not complain, because
         * that's not critical at all as we can always proceed with the root
index 2210de290b54d160d31afc937471225077bf083a..f30438970cd176e5dde188bc6e05a28c3367e451 100644 (file)
@@ -2224,6 +2224,8 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
                swab32s(&swap_header->info.version);
                swab32s(&swap_header->info.last_page);
                swab32s(&swap_header->info.nr_badpages);
+               if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
+                       return 0;
                for (i = 0; i < swap_header->info.nr_badpages; i++)
                        swab32s(&swap_header->info.badpages[i]);
        }
index a01cce450a2692bf4b3c28b105d0444256a0f176..8d8c62d89e6d101bce9373c20258d1bbc9df7fa2 100644 (file)
@@ -283,7 +283,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
 
                        if (!trylock_page(page))
                                continue;
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
                        if (PageWriteback(page)) {
                                unlock_page(page);
                                continue;
@@ -371,7 +371,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
                        }
 
                        lock_page(page);
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
                        wait_on_page_writeback(page);
                        truncate_inode_page(mapping, page);
                        unlock_page(page);
@@ -492,7 +492,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
                        if (!trylock_page(page))
                                continue;
 
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
 
                        /* Middle of THP: skip */
                        if (PageTransTail(page)) {
@@ -612,7 +612,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                        }
 
                        lock_page(page);
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
                        if (page->mapping != mapping) {
                                unlock_page(page);
                                continue;
index 662cddf914af2048ab6c9c674f59d37a7aceba69..1a41553db866f543719c019e36dc2c71c4b3b984 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -230,8 +230,10 @@ void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
 }
 
 /* Check if the vma is being used as a stack by this task */
-int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t)
+int vma_is_stack_for_current(struct vm_area_struct *vma)
 {
+       struct task_struct * __maybe_unused t = current;
+
        return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t));
 }
 
@@ -283,7 +285,8 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast);
 int __weak get_user_pages_fast(unsigned long start,
                                int nr_pages, int write, struct page **pages)
 {
-       return get_user_pages_unlocked(start, nr_pages, write, 0, pages);
+       return get_user_pages_unlocked(start, nr_pages, pages,
+                                      write ? FOLL_WRITE : 0);
 }
 EXPORT_SYMBOL_GPL(get_user_pages_fast);
 
@@ -623,7 +626,7 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
        if (len > buflen)
                len = buflen;
 
-       res = access_process_vm(task, arg_start, buffer, len, 0);
+       res = access_process_vm(task, arg_start, buffer, len, FOLL_FORCE);
 
        /*
         * If the nul at the end of args has been overwritten, then
@@ -638,7 +641,8 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen)
                        if (len > buflen - res)
                                len = buflen - res;
                        res += access_process_vm(task, env_start,
-                                                buffer+res, len, 0);
+                                                buffer+res, len,
+                                                FOLL_FORCE);
                        res = strnlen(buffer, res);
                }
        }
index 744f926af442096c36eac4b0d9259c25e7627e0e..d75cdf360730183e2f3690795b6bac8bcc594d36 100644 (file)
@@ -2354,6 +2354,8 @@ static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memc
                        }
                }
 
+               cond_resched();
+
                if (nr_reclaimed < nr_to_reclaim || scan_adjusted)
                        continue;
 
@@ -3043,7 +3045,9 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                            sc.gfp_mask,
                                            sc.reclaim_idx);
 
+       current->flags |= PF_MEMALLOC;
        nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+       current->flags &= ~PF_MEMALLOC;
 
        trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
 
index 617475f529f42aed1e1ba34565e034ed7cad8157..fb1f9183d89a360d7b7851a9083e098ff5696b8c 100644 (file)
@@ -348,7 +348,7 @@ static unsigned long count_shadow_nodes(struct shrinker *shrinker,
        shadow_nodes = list_lru_shrink_count(&workingset_shadow_nodes, sc);
        local_irq_enable();
 
-       if (memcg_kmem_enabled()) {
+       if (sc->memcg) {
                pages = mem_cgroup_node_nr_lru_pages(sc->memcg, sc->nid,
                                                     LRU_ALL_FILE);
        } else {
index 8de138d3306bdbe6f3164db323637ded5bf5b5b3..f2531ad66b68b358ea86f624763029404a262868 100644 (file)
@@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff **head,
 
        skb_gro_pull(skb, sizeof(*vhdr));
        skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
-       pp = ptype->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 
 out_unlock:
        rcu_read_unlock();
index e0e1a88c3e5807dfefea4dc0f255b69087c1f15b..d2905a855d1b9b3e55b102ec7c4b33a389395476 100644 (file)
@@ -63,7 +63,7 @@ enum batadv_dbg_level {
        BATADV_DBG_NC           = BIT(5),
        BATADV_DBG_MCAST        = BIT(6),
        BATADV_DBG_TP_METER     = BIT(7),
-       BATADV_DBG_ALL          = 127,
+       BATADV_DBG_ALL          = 255,
 };
 
 #ifdef CONFIG_BATMAN_ADV_DEBUG
index 5f3bfc41aeb1ca5e505a232a480ad5671d85265a..7c8d16086f0fddbcfb85b32e8bff9223befce0ab 100644 (file)
@@ -544,7 +544,7 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
        if (bat_priv->algo_ops->neigh.hardif_init)
                bat_priv->algo_ops->neigh.hardif_init(hardif_neigh);
 
-       hlist_add_head(&hardif_neigh->list, &hard_iface->neigh_list);
+       hlist_add_head_rcu(&hardif_neigh->list, &hard_iface->neigh_list);
 
 out:
        spin_unlock_bh(&hard_iface->neigh_list_lock);
index 2333777f919d8ef3e28055733e0d55b64d3ecff3..8af1611b8ab2c21e53b9c46bf74a9fa677d805a4 100644 (file)
@@ -837,6 +837,7 @@ static int batadv_tp_send(void *arg)
        primary_if = batadv_primary_if_get_selected(bat_priv);
        if (unlikely(!primary_if)) {
                err = BATADV_TP_REASON_DST_UNREACHABLE;
+               tp_vars->reason = err;
                goto out;
        }
 
index 7f663092f6de49831680600b2a83aedc15904bac..0dc85eb1cb7addd08a8b3071e076fcacd784e4e2 100644 (file)
@@ -3282,7 +3282,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
                                                             &tvlv_tt_data,
                                                             &tt_change,
                                                             &tt_len);
-               if (!tt_len)
+               if (!tt_len || !tvlv_len)
                        goto unlock;
 
                /* Copy the last orig_node's OGM buffer */
@@ -3300,7 +3300,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
                                                             &tvlv_tt_data,
                                                             &tt_change,
                                                             &tt_len);
-               if (!tt_len)
+               if (!tt_len || !tvlv_len)
                        goto out;
 
                /* fill the rest of the tvlv with the real TT entries */
index d020299baba41253022ca277711801bc9732828c..1904a93f47d50a2bd1c2c1651f48b1ab762ece3c 100644 (file)
@@ -1090,7 +1090,6 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
 {
        struct hci_conn *hcon;
        struct hci_dev *hdev;
-       bdaddr_t *src = BDADDR_ANY;
        int n;
 
        n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
@@ -1101,7 +1100,8 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
        if (n < 7)
                return -EINVAL;
 
-       hdev = hci_get_route(addr, src);
+       /* The LE_PUBLIC address type is ignored because of BDADDR_ANY */
+       hdev = hci_get_route(addr, BDADDR_ANY, BDADDR_LE_PUBLIC);
        if (!hdev)
                return -ENOENT;
 
index 3809617aa98d83c428fc56606e0aa05562272c40..dc59eae5471788e42091ba7fc907585d36e99c2d 100644 (file)
@@ -613,7 +613,7 @@ int hci_conn_del(struct hci_conn *conn)
        return 0;
 }
 
-struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
 {
        int use_src = bacmp(src, BDADDR_ANY);
        struct hci_dev *hdev = NULL, *d;
@@ -634,7 +634,29 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
                 */
 
                if (use_src) {
-                       if (!bacmp(&d->bdaddr, src)) {
+                       bdaddr_t id_addr;
+                       u8 id_addr_type;
+
+                       if (src_type == BDADDR_BREDR) {
+                               if (!lmp_bredr_capable(d))
+                                       continue;
+                               bacpy(&id_addr, &d->bdaddr);
+                               id_addr_type = BDADDR_BREDR;
+                       } else {
+                               if (!lmp_le_capable(d))
+                                       continue;
+
+                               hci_copy_identity_address(d, &id_addr,
+                                                         &id_addr_type);
+
+                               /* Convert from HCI to three-value type */
+                               if (id_addr_type == ADDR_LE_DEV_PUBLIC)
+                                       id_addr_type = BDADDR_LE_PUBLIC;
+                               else
+                                       id_addr_type = BDADDR_LE_RANDOM;
+                       }
+
+                       if (!bacmp(&id_addr, src) && id_addr_type == src_type) {
                                hdev = d; break;
                        }
                } else {
index e2288421fe6b79775d1bb3ddde69341782298cc7..1015d9c8d97ddbe978ae7b54698b093f1961b958 100644 (file)
@@ -969,41 +969,38 @@ void __hci_req_enable_advertising(struct hci_request *req)
        hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
 }
 
-static u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
+u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
 {
-       size_t complete_len;
        size_t short_len;
-       int max_len;
-
-       max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
-       complete_len = strlen(hdev->dev_name);
-       short_len = strlen(hdev->short_name);
-
-       /* no space left for name */
-       if (max_len < 1)
-               return ad_len;
+       size_t complete_len;
 
-       /* no name set */
-       if (!complete_len)
+       /* no space left for name (+ NULL + type + len) */
+       if ((HCI_MAX_AD_LENGTH - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3)
                return ad_len;
 
-       /* complete name fits and is eq to max short name len or smaller */
-       if (complete_len <= max_len &&
-           complete_len <= HCI_MAX_SHORT_NAME_LENGTH) {
+       /* use complete name if present and fits */
+       complete_len = strlen(hdev->dev_name);
+       if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH)
                return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE,
-                                      hdev->dev_name, complete_len);
-       }
+                                      hdev->dev_name, complete_len + 1);
 
-       /* short name set and fits */
-       if (short_len && short_len <= max_len) {
+       /* use short name if present */
+       short_len = strlen(hdev->short_name);
+       if (short_len)
                return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,
-                                      hdev->short_name, short_len);
-       }
+                                      hdev->short_name, short_len + 1);
 
-       /* no short name set so shorten complete name */
-       if (!short_len) {
-               return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,
-                                      hdev->dev_name, max_len);
+       /* use shortened full name if present, we already know that name
+        * is longer then HCI_MAX_SHORT_NAME_LENGTH
+        */
+       if (complete_len) {
+               u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1];
+
+               memcpy(name, hdev->dev_name, HCI_MAX_SHORT_NAME_LENGTH);
+               name[HCI_MAX_SHORT_NAME_LENGTH] = '\0';
+
+               return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, name,
+                                      sizeof(name));
        }
 
        return ad_len;
index 6b06629245a8c0358a5f1c6bf8964d66f291d0a6..dde77bd59f915a48c4ea64c0444d61ac50151f67 100644 (file)
@@ -106,6 +106,8 @@ static inline void hci_update_background_scan(struct hci_dev *hdev)
 void hci_request_setup(struct hci_dev *hdev);
 void hci_request_cancel_all(struct hci_dev *hdev);
 
+u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len);
+
 static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type,
                                  u8 *data, u8 data_len)
 {
index d4cad29b033fc6d8601913013f291ab287648928..577f1c01454a566cc63431ff8bb76f08785431ca 100644 (file)
@@ -7060,7 +7060,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
        BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
               dst_type, __le16_to_cpu(psm));
 
-       hdev = hci_get_route(dst, &chan->src);
+       hdev = hci_get_route(dst, &chan->src, chan->src_type);
        if (!hdev)
                return -EHOSTUNREACH;
 
index 736038085feb403f6b93cb2473cb5cb747b6d842..1fba2a03f8ae8a25c95737ed963a894321ce8288 100644 (file)
@@ -6017,7 +6017,15 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
        return err;
 }
 
-static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
+static u8 calculate_name_len(struct hci_dev *hdev)
+{
+       u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
+
+       return append_local_name(hdev, buf, 0);
+}
+
+static u8 tlv_data_max_len(struct hci_dev *hdev, u32 adv_flags,
+                          bool is_adv_data)
 {
        u8 max_len = HCI_MAX_AD_LENGTH;
 
@@ -6030,9 +6038,8 @@ static u8 tlv_data_max_len(u32 adv_flags, bool is_adv_data)
                if (adv_flags & MGMT_ADV_FLAG_TX_POWER)
                        max_len -= 3;
        } else {
-               /* at least 1 byte of name should fit in */
                if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME)
-                       max_len -= 3;
+                       max_len -= calculate_name_len(hdev);
 
                if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE))
                        max_len -= 4;
@@ -6063,12 +6070,13 @@ static bool appearance_managed(u32 adv_flags)
        return adv_flags & MGMT_ADV_FLAG_APPEARANCE;
 }
 
-static bool tlv_data_is_valid(u32 adv_flags, u8 *data, u8 len, bool is_adv_data)
+static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
+                             u8 len, bool is_adv_data)
 {
        int i, cur_len;
        u8 max_len;
 
-       max_len = tlv_data_max_len(adv_flags, is_adv_data);
+       max_len = tlv_data_max_len(hdev, adv_flags, is_adv_data);
 
        if (len > max_len)
                return false;
@@ -6215,8 +6223,8 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       if (!tlv_data_is_valid(flags, cp->data, cp->adv_data_len, true) ||
-           !tlv_data_is_valid(flags, cp->data + cp->adv_data_len,
+       if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) ||
+           !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
                               cp->scan_rsp_len, false)) {
                err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                      MGMT_STATUS_INVALID_PARAMS);
@@ -6429,8 +6437,8 @@ static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
 
        rp.instance = cp->instance;
        rp.flags = cp->flags;
-       rp.max_adv_data_len = tlv_data_max_len(flags, true);
-       rp.max_scan_rsp_len = tlv_data_max_len(flags, false);
+       rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
+       rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
 
        err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
                                MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
index 8e385a0ae60e0bd6e4b1ed7615905a7170c4a8bc..2f2cb5e27cdd4dc9b6079b5d602c89e510bd9ab8 100644 (file)
@@ -178,7 +178,7 @@ static void rfcomm_reparent_device(struct rfcomm_dev *dev)
        struct hci_dev *hdev;
        struct hci_conn *conn;
 
-       hdev = hci_get_route(&dev->dst, &dev->src);
+       hdev = hci_get_route(&dev->dst, &dev->src, BDADDR_BREDR);
        if (!hdev)
                return;
 
index f52bcbf2e58cd8b8ded4c3d65c8dd9b87034b002..3125ce670c2f241f446daae17a37fbcc5f485574 100644 (file)
@@ -219,7 +219,7 @@ static int sco_connect(struct sock *sk)
 
        BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst);
 
-       hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src);
+       hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
        if (!hdev)
                return -EHOSTUNREACH;
 
index c5fea9393946f64af336873645db82d09599d442..2136e45f5277764264c181b201664822edef4c17 100644 (file)
@@ -972,13 +972,12 @@ static void br_multicast_enable(struct bridge_mcast_own_query *query)
                mod_timer(&query->timer, jiffies);
 }
 
-void br_multicast_enable_port(struct net_bridge_port *port)
+static void __br_multicast_enable_port(struct net_bridge_port *port)
 {
        struct net_bridge *br = port->br;
 
-       spin_lock(&br->multicast_lock);
        if (br->multicast_disabled || !netif_running(br->dev))
-               goto out;
+               return;
 
        br_multicast_enable(&port->ip4_own_query);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -987,8 +986,14 @@ void br_multicast_enable_port(struct net_bridge_port *port)
        if (port->multicast_router == MDB_RTR_TYPE_PERM &&
            hlist_unhashed(&port->rlist))
                br_multicast_add_router(br, port);
+}
 
-out:
+void br_multicast_enable_port(struct net_bridge_port *port)
+{
+       struct net_bridge *br = port->br;
+
+       spin_lock(&br->multicast_lock);
+       __br_multicast_enable_port(port);
        spin_unlock(&br->multicast_lock);
 }
 
@@ -1994,8 +1999,9 @@ static void br_multicast_start_querier(struct net_bridge *br,
 
 int br_multicast_toggle(struct net_bridge *br, unsigned long val)
 {
-       int err = 0;
        struct net_bridge_mdb_htable *mdb;
+       struct net_bridge_port *port;
+       int err = 0;
 
        spin_lock_bh(&br->multicast_lock);
        if (br->multicast_disabled == !val)
@@ -2023,10 +2029,9 @@ rollback:
                        goto rollback;
        }
 
-       br_multicast_start_querier(br, &br->ip4_own_query);
-#if IS_ENABLED(CONFIG_IPV6)
-       br_multicast_start_querier(br, &br->ip6_own_query);
-#endif
+       br_multicast_open(br);
+       list_for_each_entry(port, &br->port_list, list)
+               __br_multicast_enable_port(port);
 
 unlock:
        spin_unlock_bh(&br->multicast_lock);
index e120307c6e36ab1173232ee1d4fb1730f5dbae60..f88c4df3f91efc1464a3db29ef961714a2f40506 100644 (file)
@@ -898,6 +898,7 @@ int br_sysfs_addbr(struct net_device *dev)
        if (!br->ifobj) {
                pr_info("%s: can't add kobject (directory) %s/%s\n",
                        __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
+               err = -ENOMEM;
                goto out3;
        }
        return 0;
index aa209b1066c9699a12510055e70ae79b33ee05b7..92cbbd2afddbf1bfb6a79d2fc7112fdb63b3711e 100644 (file)
@@ -1107,10 +1107,7 @@ static struct net_proto_family caif_family_ops = {
 
 static int __init caif_sktinit_module(void)
 {
-       int err = sock_register(&caif_family_ops);
-       if (!err)
-               return err;
-       return 0;
+       return sock_register(&caif_family_ops);
 }
 
 static void __exit caif_sktexit_module(void)
index 8e999ffdf28be91fb444b53cef62a34b582f6ba3..436a7537e6a9d3ef065ec572568c42fd13331b5e 100644 (file)
@@ -77,7 +77,7 @@
                     (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \
                     (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG))
 
-#define CAN_BCM_VERSION "20160617"
+#define CAN_BCM_VERSION "20161123"
 
 MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
 MODULE_LICENSE("Dual BSD/GPL");
@@ -109,8 +109,9 @@ struct bcm_op {
        u32 count;
        u32 nframes;
        u32 currframe;
-       struct canfd_frame *frames;
-       struct canfd_frame *last_frames;
+       /* void pointers to arrays of struct can[fd]_frame */
+       void *frames;
+       void *last_frames;
        struct canfd_frame sframe;
        struct canfd_frame last_sframe;
        struct sock *sk;
@@ -681,7 +682,7 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
 
        if (op->flags & RX_FILTER_ID) {
                /* the easiest case */
-               bcm_rx_update_and_send(op, &op->last_frames[0], rxframe);
+               bcm_rx_update_and_send(op, op->last_frames, rxframe);
                goto rx_starttimer;
        }
 
@@ -1068,7 +1069,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
 
                if (msg_head->nframes) {
                        /* update CAN frames content */
-                       err = memcpy_from_msg((u8 *)op->frames, msg,
+                       err = memcpy_from_msg(op->frames, msg,
                                              msg_head->nframes * op->cfsiz);
                        if (err < 0)
                                return err;
@@ -1118,7 +1119,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                }
 
                if (msg_head->nframes) {
-                       err = memcpy_from_msg((u8 *)op->frames, msg,
+                       err = memcpy_from_msg(op->frames, msg,
                                              msg_head->nframes * op->cfsiz);
                        if (err < 0) {
                                if (op->frames != &op->sframe)
@@ -1163,6 +1164,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
        /* check flags */
 
        if (op->flags & RX_RTR_FRAME) {
+               struct canfd_frame *frame0 = op->frames;
 
                /* no timers in RTR-mode */
                hrtimer_cancel(&op->thrtimer);
@@ -1174,8 +1176,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                 * prevent a full-load-loopback-test ... ;-]
                 */
                if ((op->flags & TX_CP_CAN_ID) ||
-                   (op->frames[0].can_id == op->can_id))
-                       op->frames[0].can_id = op->can_id & ~CAN_RTR_FLAG;
+                   (frame0->can_id == op->can_id))
+                       frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
 
        } else {
                if (op->flags & SETTIMER) {
@@ -1549,24 +1551,31 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
        struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
        struct sock *sk = sock->sk;
        struct bcm_sock *bo = bcm_sk(sk);
+       int ret = 0;
 
        if (len < sizeof(*addr))
                return -EINVAL;
 
-       if (bo->bound)
-               return -EISCONN;
+       lock_sock(sk);
+
+       if (bo->bound) {
+               ret = -EISCONN;
+               goto fail;
+       }
 
        /* bind a device to this socket */
        if (addr->can_ifindex) {
                struct net_device *dev;
 
                dev = dev_get_by_index(&init_net, addr->can_ifindex);
-               if (!dev)
-                       return -ENODEV;
-
+               if (!dev) {
+                       ret = -ENODEV;
+                       goto fail;
+               }
                if (dev->type != ARPHRD_CAN) {
                        dev_put(dev);
-                       return -ENODEV;
+                       ret = -ENODEV;
+                       goto fail;
                }
 
                bo->ifindex = dev->ifindex;
@@ -1577,17 +1586,24 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
                bo->ifindex = 0;
        }
 
-       bo->bound = 1;
-
        if (proc_dir) {
                /* unique socket address as filename */
                sprintf(bo->procname, "%lu", sock_i_ino(sk));
                bo->bcm_proc_read = proc_create_data(bo->procname, 0644,
                                                     proc_dir,
                                                     &bcm_proc_fops, sk);
+               if (!bo->bcm_proc_read) {
+                       ret = -ENOMEM;
+                       goto fail;
+               }
        }
 
-       return 0;
+       bo->bound = 1;
+
+fail:
+       release_sock(sk);
+
+       return ret;
 }
 
 static int bcm_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
index 972c187d40abb0f54a30a076e60359a5f1878a0c..b075f028d7e23958e9433a4b19f4475ad930b547 100644 (file)
@@ -499,6 +499,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
                if (optlen % sizeof(struct can_filter) != 0)
                        return -EINVAL;
 
+               if (optlen > CAN_RAW_FILTER_MAX * sizeof(struct can_filter))
+                       return -EINVAL;
+
                count = optlen / sizeof(struct can_filter);
 
                if (count > 1) {
index 7d54e944de5e0723918d8196e2d10766fd0b84c5..dcbe67ff3e2b281abc87d791def2f131fdba9fb3 100644 (file)
@@ -34,7 +34,8 @@ void ceph_file_layout_from_legacy(struct ceph_file_layout *fl,
        fl->stripe_count = le32_to_cpu(legacy->fl_stripe_count);
        fl->object_size = le32_to_cpu(legacy->fl_object_size);
        fl->pool_id = le32_to_cpu(legacy->fl_pg_pool);
-       if (fl->pool_id == 0)
+       if (fl->pool_id == 0 && fl->stripe_unit == 0 &&
+           fl->stripe_count == 0 && fl->object_size == 0)
                fl->pool_id = -1;
 }
 EXPORT_SYMBOL(ceph_file_layout_from_legacy);
index d9bf7a1d0a583730a9f4c7376102d1ce5694f66f..e6ae15bc41b74dfc96e9d967139367b4ad3be952 100644 (file)
@@ -4094,6 +4094,7 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
        osd_init(&osdc->homeless_osd);
        osdc->homeless_osd.o_osdc = osdc;
        osdc->homeless_osd.o_osd = CEPH_HOMELESS_OSD;
+       osdc->last_linger_id = CEPH_LINGER_ID_START;
        osdc->linger_requests = RB_ROOT;
        osdc->map_checks = RB_ROOT;
        osdc->linger_map_checks = RB_ROOT;
index 00d2601407c5dfd5b8e8a94bf5de2160ae29cc38..1a7c9a79a53c22e8e61e3b6e8e1720db71d9f9a9 100644 (file)
@@ -26,7 +26,7 @@ struct page **ceph_get_direct_page_vector(const void __user *data,
        while (got < num_pages) {
                rc = get_user_pages_unlocked(
                    (unsigned long)data + ((unsigned long)got * PAGE_SIZE),
-                   num_pages - got, write_page, 0, pages + got);
+                   num_pages - got, pages + got, write_page ? FOLL_WRITE : 0);
                if (rc < 0)
                        break;
                BUG_ON(rc == 0);
index 4bc19a164ba5dc1dbf5d0f3f378f61e49d3be9dd..6666b28b6815e1665218af967bc9e3adbb87b86f 100644 (file)
@@ -1766,19 +1766,14 @@ EXPORT_SYMBOL_GPL(is_skb_forwardable);
 
 int __dev_forward_skb(struct net_device *dev, struct sk_buff *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;
-       }
+       int ret = ____dev_forward_skb(dev, skb);
 
-       skb_scrub_packet(skb, true);
-       skb->priority = 0;
-       skb->protocol = eth_type_trans(skb, dev);
-       skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+       if (likely(!ret)) {
+               skb->protocol = eth_type_trans(skb, dev);
+               skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+       }
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(__dev_forward_skb);
 
@@ -2484,7 +2479,7 @@ int skb_checksum_help(struct sk_buff *skb)
                        goto out;
        }
 
-       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+       *(__sum16 *)(skb->data + offset) = csum_fold(csum) ?: CSUM_MANGLED_0;
 out_set_summed:
        skb->ip_summed = CHECKSUM_NONE;
 out:
@@ -3035,6 +3030,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
        }
        return head;
 }
+EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
 
 static void qdisc_pkt_len_init(struct sk_buff *skb)
 {
@@ -4511,6 +4507,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
                NAPI_GRO_CB(skb)->flush = 0;
                NAPI_GRO_CB(skb)->free = 0;
                NAPI_GRO_CB(skb)->encap_mark = 0;
+               NAPI_GRO_CB(skb)->recursion_counter = 0;
                NAPI_GRO_CB(skb)->is_fou = 0;
                NAPI_GRO_CB(skb)->is_atomic = 1;
                NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
@@ -5511,10 +5508,14 @@ struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
 {
        struct netdev_adjacent *lower;
 
-       lower = list_first_or_null_rcu(&dev->all_adj_list.lower,
-                                      struct netdev_adjacent, list);
+       lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list);
 
-       return lower ? lower->dev : NULL;
+       if (&lower->list == &dev->all_adj_list.lower)
+               return NULL;
+
+       *iter = &lower->list;
+
+       return lower->dev;
 }
 EXPORT_SYMBOL(netdev_all_lower_get_next_rcu);
 
index 977489820eb957098705c9ea1674ed3092a6cfe6..047a1752ece183b2b2affa5bd0e7a08886530b1d 100644 (file)
@@ -2479,6 +2479,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GET_TS_INFO:
        case ETHTOOL_GEEE:
        case ETHTOOL_GTUNABLE:
+       case ETHTOOL_GLINKSETTINGS:
                break;
        default:
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
index 00351cdf7d0c3f5fe1657e02b96b7a90891e0385..b391209838efa914948a2c178661089c4eb124d5 100644 (file)
@@ -1628,6 +1628,19 @@ static inline int __bpf_rx_skb(struct net_device *dev, struct sk_buff *skb)
        return dev_forward_skb(dev, skb);
 }
 
+static inline int __bpf_rx_skb_no_mac(struct net_device *dev,
+                                     struct sk_buff *skb)
+{
+       int ret = ____dev_forward_skb(dev, skb);
+
+       if (likely(!ret)) {
+               skb->dev = dev;
+               ret = netif_rx(skb);
+       }
+
+       return ret;
+}
+
 static inline int __bpf_tx_skb(struct net_device *dev, struct sk_buff *skb)
 {
        int ret;
@@ -1647,6 +1660,51 @@ static inline int __bpf_tx_skb(struct net_device *dev, struct sk_buff *skb)
        return ret;
 }
 
+static int __bpf_redirect_no_mac(struct sk_buff *skb, struct net_device *dev,
+                                u32 flags)
+{
+       /* skb->mac_len is not set on normal egress */
+       unsigned int mlen = skb->network_header - skb->mac_header;
+
+       __skb_pull(skb, mlen);
+
+       /* At ingress, the mac header has already been pulled once.
+        * At egress, skb_pospull_rcsum has to be done in case that
+        * the skb is originated from ingress (i.e. a forwarded skb)
+        * to ensure that rcsum starts at net header.
+        */
+       if (!skb_at_tc_ingress(skb))
+               skb_postpull_rcsum(skb, skb_mac_header(skb), mlen);
+       skb_pop_mac_header(skb);
+       skb_reset_mac_len(skb);
+       return flags & BPF_F_INGRESS ?
+              __bpf_rx_skb_no_mac(dev, skb) : __bpf_tx_skb(dev, skb);
+}
+
+static int __bpf_redirect_common(struct sk_buff *skb, struct net_device *dev,
+                                u32 flags)
+{
+       bpf_push_mac_rcsum(skb);
+       return flags & BPF_F_INGRESS ?
+              __bpf_rx_skb(dev, skb) : __bpf_tx_skb(dev, skb);
+}
+
+static int __bpf_redirect(struct sk_buff *skb, struct net_device *dev,
+                         u32 flags)
+{
+       switch (dev->type) {
+       case ARPHRD_TUNNEL:
+       case ARPHRD_TUNNEL6:
+       case ARPHRD_SIT:
+       case ARPHRD_IPGRE:
+       case ARPHRD_VOID:
+       case ARPHRD_NONE:
+               return __bpf_redirect_no_mac(skb, dev, flags);
+       default:
+               return __bpf_redirect_common(skb, dev, flags);
+       }
+}
+
 BPF_CALL_3(bpf_clone_redirect, struct sk_buff *, skb, u32, ifindex, u64, flags)
 {
        struct net_device *dev;
@@ -1675,10 +1733,7 @@ BPF_CALL_3(bpf_clone_redirect, struct sk_buff *, skb, u32, ifindex, u64, flags)
                return -ENOMEM;
        }
 
-       bpf_push_mac_rcsum(clone);
-
-       return flags & BPF_F_INGRESS ?
-              __bpf_rx_skb(dev, clone) : __bpf_tx_skb(dev, clone);
+       return __bpf_redirect(clone, dev, flags);
 }
 
 static const struct bpf_func_proto bpf_clone_redirect_proto = {
@@ -1722,10 +1777,7 @@ int skb_do_redirect(struct sk_buff *skb)
                return -EINVAL;
        }
 
-       bpf_push_mac_rcsum(skb);
-
-       return ri->flags & BPF_F_INGRESS ?
-              __bpf_rx_skb(dev, skb) : __bpf_tx_skb(dev, skb);
+       return __bpf_redirect(skb, dev, ri->flags);
 }
 
 static const struct bpf_func_proto bpf_redirect_proto = {
index 3937b1b68d5bc7ad50691716ac1612332a5dc997..18e8893d4be59905ba1053fffea7cc16d0e054af 100644 (file)
@@ -95,7 +95,6 @@ static void flow_cache_gc_task(struct work_struct *work)
        list_for_each_entry_safe(fce, n, &gc_list, u.gc_list) {
                flow_entry_kill(fce, xfrm);
                atomic_dec(&xfrm->flow_cache_gc_count);
-               WARN_ON(atomic_read(&xfrm->flow_cache_gc_count) < 0);
        }
 }
 
@@ -236,9 +235,8 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
                if (fcp->hash_count > fc->high_watermark)
                        flow_cache_shrink(fc, fcp);
 
-               if (fcp->hash_count > 2 * fc->high_watermark ||
-                   atomic_read(&net->xfrm.flow_cache_gc_count) > fc->high_watermark) {
-                       atomic_inc(&net->xfrm.flow_cache_genid);
+               if (atomic_read(&net->xfrm.flow_cache_gc_count) >
+                   2 * num_online_cpus() * fc->high_watermark) {
                        flo = ERR_PTR(-ENOBUFS);
                        goto ret_object;
                }
index 1a7b80f733764770c3ac44853314eec2837c0abd..c6d8207ffa7e9ec6247a608bbbfbb5fc6a1076f7 100644 (file)
@@ -122,7 +122,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
        struct flow_dissector_key_keyid *key_keyid;
        bool skip_vlan = false;
        u8 ip_proto = 0;
-       bool ret = false;
+       bool ret;
 
        if (!data) {
                data = skb->data;
@@ -246,15 +246,13 @@ ipv6:
        case htons(ETH_P_8021AD):
        case htons(ETH_P_8021Q): {
                const struct vlan_hdr *vlan;
+               struct vlan_hdr _vlan;
+               bool vlan_tag_present = skb && skb_vlan_tag_present(skb);
 
-               if (skb_vlan_tag_present(skb))
+               if (vlan_tag_present)
                        proto = skb->protocol;
 
-               if (!skb_vlan_tag_present(skb) ||
-                   proto == cpu_to_be16(ETH_P_8021Q) ||
-                   proto == cpu_to_be16(ETH_P_8021AD)) {
-                       struct vlan_hdr _vlan;
-
+               if (!vlan_tag_present || eth_type_vlan(skb->protocol)) {
                        vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan),
                                                    data, hlen, &_vlan);
                        if (!vlan)
@@ -272,7 +270,7 @@ ipv6:
                                                             FLOW_DISSECTOR_KEY_VLAN,
                                                             target_container);
 
-                       if (skb_vlan_tag_present(skb)) {
+                       if (vlan_tag_present) {
                                key_vlan->vlan_id = skb_vlan_tag_get_id(skb);
                                key_vlan->vlan_priority =
                                        (skb_vlan_tag_get_prio(skb) >> VLAN_PRIO_SHIFT);
@@ -551,12 +549,17 @@ ip_proto_again:
 out_good:
        ret = true;
 
-out_bad:
+       key_control->thoff = (u16)nhoff;
+out:
        key_basic->n_proto = proto;
        key_basic->ip_proto = ip_proto;
-       key_control->thoff = (u16)nhoff;
 
        return ret;
+
+out_bad:
+       ret = false;
+       key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
+       goto out;
 }
 EXPORT_SYMBOL(__skb_flow_dissect);
 
@@ -1010,4 +1013,4 @@ static int __init init_default_flow_dissectors(void)
        return 0;
 }
 
-late_initcall_sync(init_default_flow_dissectors);
+core_initcall(init_default_flow_dissectors);
index 989434f36f963d69d102ba46fbc54ec9d28bbd09..7001da910c6b26cb2300c38147305a459895cc49 100644 (file)
@@ -215,13 +215,16 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id);
  */
 int peernet2id_alloc(struct net *net, struct net *peer)
 {
+       unsigned long flags;
        bool alloc;
        int id;
 
-       spin_lock_bh(&net->nsid_lock);
+       if (atomic_read(&net->count) == 0)
+               return NETNSA_NSID_NOT_ASSIGNED;
+       spin_lock_irqsave(&net->nsid_lock, flags);
        alloc = atomic_read(&peer->count) == 0 ? false : true;
        id = __peernet2id_alloc(net, peer, &alloc);
-       spin_unlock_bh(&net->nsid_lock);
+       spin_unlock_irqrestore(&net->nsid_lock, flags);
        if (alloc && id >= 0)
                rtnl_net_notifyid(net, RTM_NEWNSID, id);
        return id;
@@ -230,11 +233,12 @@ int peernet2id_alloc(struct net *net, struct net *peer)
 /* This function returns, if assigned, the id of a peer netns. */
 int peernet2id(struct net *net, struct net *peer)
 {
+       unsigned long flags;
        int id;
 
-       spin_lock_bh(&net->nsid_lock);
+       spin_lock_irqsave(&net->nsid_lock, flags);
        id = __peernet2id(net, peer);
-       spin_unlock_bh(&net->nsid_lock);
+       spin_unlock_irqrestore(&net->nsid_lock, flags);
        return id;
 }
 EXPORT_SYMBOL(peernet2id);
@@ -249,17 +253,18 @@ bool peernet_has_id(struct net *net, struct net *peer)
 
 struct net *get_net_ns_by_id(struct net *net, int id)
 {
+       unsigned long flags;
        struct net *peer;
 
        if (id < 0)
                return NULL;
 
        rcu_read_lock();
-       spin_lock_bh(&net->nsid_lock);
+       spin_lock_irqsave(&net->nsid_lock, flags);
        peer = idr_find(&net->netns_ids, id);
        if (peer)
                get_net(peer);
-       spin_unlock_bh(&net->nsid_lock);
+       spin_unlock_irqrestore(&net->nsid_lock, flags);
        rcu_read_unlock();
 
        return peer;
@@ -422,17 +427,17 @@ static void cleanup_net(struct work_struct *work)
                for_each_net(tmp) {
                        int id;
 
-                       spin_lock_bh(&tmp->nsid_lock);
+                       spin_lock_irq(&tmp->nsid_lock);
                        id = __peernet2id(tmp, net);
                        if (id >= 0)
                                idr_remove(&tmp->netns_ids, id);
-                       spin_unlock_bh(&tmp->nsid_lock);
+                       spin_unlock_irq(&tmp->nsid_lock);
                        if (id >= 0)
                                rtnl_net_notifyid(tmp, RTM_DELNSID, id);
                }
-               spin_lock_bh(&net->nsid_lock);
+               spin_lock_irq(&net->nsid_lock);
                idr_destroy(&net->netns_ids);
-               spin_unlock_bh(&net->nsid_lock);
+               spin_unlock_irq(&net->nsid_lock);
 
        }
        rtnl_unlock();
@@ -561,6 +566,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct net *net = sock_net(skb->sk);
        struct nlattr *tb[NETNSA_MAX + 1];
+       unsigned long flags;
        struct net *peer;
        int nsid, err;
 
@@ -581,15 +587,15 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (IS_ERR(peer))
                return PTR_ERR(peer);
 
-       spin_lock_bh(&net->nsid_lock);
+       spin_lock_irqsave(&net->nsid_lock, flags);
        if (__peernet2id(net, peer) >= 0) {
-               spin_unlock_bh(&net->nsid_lock);
+               spin_unlock_irqrestore(&net->nsid_lock, flags);
                err = -EEXIST;
                goto out;
        }
 
        err = alloc_netid(net, peer, nsid);
-       spin_unlock_bh(&net->nsid_lock);
+       spin_unlock_irqrestore(&net->nsid_lock, flags);
        if (err >= 0) {
                rtnl_net_notifyid(net, RTM_NEWNSID, err);
                err = 0;
@@ -711,10 +717,11 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
                .idx = 0,
                .s_idx = cb->args[0],
        };
+       unsigned long flags;
 
-       spin_lock_bh(&net->nsid_lock);
+       spin_lock_irqsave(&net->nsid_lock, flags);
        idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
-       spin_unlock_bh(&net->nsid_lock);
+       spin_unlock_irqrestore(&net->nsid_lock, flags);
 
        cb->args[0] = net_cb.idx;
        return skb->len;
index 5219a9e2127aeda719fce840e594cf0f4fe058e7..306b8f0e03c18b32846491947932418243e416f8 100644 (file)
 #define M_QUEUE_XMIT           2       /* Inject packet into qdisc */
 
 /* If lock -- protects updating of if_list */
-#define   if_lock(t)           spin_lock(&(t->if_lock));
-#define   if_unlock(t)           spin_unlock(&(t->if_lock));
+#define   if_lock(t)           mutex_lock(&(t->if_lock));
+#define   if_unlock(t)           mutex_unlock(&(t->if_lock));
 
 /* Used to help with determining the pkts on receive */
 #define PKTGEN_MAGIC 0xbe9be955
@@ -423,7 +423,7 @@ struct pktgen_net {
 };
 
 struct pktgen_thread {
-       spinlock_t if_lock;             /* for list of devices */
+       struct mutex if_lock;           /* for list of devices */
        struct list_head if_list;       /* All device here */
        struct list_head th_list;
        struct task_struct *tsk;
@@ -2010,11 +2010,13 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d
 {
        struct pktgen_thread *t;
 
+       mutex_lock(&pktgen_thread_lock);
+
        list_for_each_entry(t, &pn->pktgen_threads, th_list) {
                struct pktgen_dev *pkt_dev;
 
-               rcu_read_lock();
-               list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
+               if_lock(t);
+               list_for_each_entry(pkt_dev, &t->if_list, list) {
                        if (pkt_dev->odev != dev)
                                continue;
 
@@ -2029,8 +2031,9 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d
                                       dev->name);
                        break;
                }
-               rcu_read_unlock();
+               if_unlock(t);
        }
+       mutex_unlock(&pktgen_thread_lock);
 }
 
 static int pktgen_device_event(struct notifier_block *unused,
@@ -3762,7 +3765,7 @@ static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
                return -ENOMEM;
        }
 
-       spin_lock_init(&t->if_lock);
+       mutex_init(&t->if_lock);
        t->cpu = cpu;
 
        INIT_LIST_HEAD(&t->if_list);
index fb7348f135014fcea21b621ab30e1ad02b62448d..a6196cf844f6644782fa8c3a743f35db7b9af33e 100644 (file)
@@ -275,6 +275,7 @@ int rtnl_unregister(int protocol, int msgtype)
 
        rtnl_msg_handlers[protocol][msgindex].doit = NULL;
        rtnl_msg_handlers[protocol][msgindex].dumpit = NULL;
+       rtnl_msg_handlers[protocol][msgindex].calcit = NULL;
 
        return 0;
 }
@@ -839,18 +840,20 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev,
        if (dev->dev.parent && dev_is_pci(dev->dev.parent) &&
            (ext_filter_mask & RTEXT_FILTER_VF)) {
                int num_vfs = dev_num_vf(dev->dev.parent);
-               size_t size = nla_total_size(sizeof(struct nlattr));
-               size += nla_total_size(num_vfs * sizeof(struct nlattr));
+               size_t size = nla_total_size(0);
                size += num_vfs *
-                       (nla_total_size(sizeof(struct ifla_vf_mac)) +
-                        nla_total_size(MAX_VLAN_LIST_LEN *
-                                       sizeof(struct nlattr)) +
+                       (nla_total_size(0) +
+                        nla_total_size(sizeof(struct ifla_vf_mac)) +
+                        nla_total_size(sizeof(struct ifla_vf_vlan)) +
+                        nla_total_size(0) + /* nest IFLA_VF_VLAN_LIST */
                         nla_total_size(MAX_VLAN_LIST_LEN *
                                        sizeof(struct ifla_vf_vlan_info)) +
                         nla_total_size(sizeof(struct ifla_vf_spoofchk)) +
+                        nla_total_size(sizeof(struct ifla_vf_tx_rate)) +
                         nla_total_size(sizeof(struct ifla_vf_rate)) +
                         nla_total_size(sizeof(struct ifla_vf_link_state)) +
                         nla_total_size(sizeof(struct ifla_vf_rss_query_en)) +
+                        nla_total_size(0) + /* nest IFLA_VF_STATS */
                         /* IFLA_VF_STATS_RX_PACKETS */
                         nla_total_size_64bit(sizeof(__u64)) +
                         /* IFLA_VF_STATS_TX_PACKETS */
@@ -898,7 +901,8 @@ static size_t rtnl_port_size(const struct net_device *dev,
 
 static size_t rtnl_xdp_size(const struct net_device *dev)
 {
-       size_t xdp_size = nla_total_size(1);    /* XDP_ATTACHED */
+       size_t xdp_size = nla_total_size(0) +   /* nest IFLA_XDP */
+                         nla_total_size(1);    /* XDP_ATTACHED */
 
        if (!dev->netdev_ops->ndo_xdp)
                return 0;
@@ -927,8 +931,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
               + nla_total_size(4) /* IFLA_PROMISCUITY */
               + nla_total_size(4) /* IFLA_NUM_TX_QUEUES */
               + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */
-              + nla_total_size(4) /* IFLA_MAX_GSO_SEGS */
-              + nla_total_size(4) /* IFLA_MAX_GSO_SIZE */
+              + nla_total_size(4) /* IFLA_GSO_MAX_SEGS */
+              + nla_total_size(4) /* IFLA_GSO_MAX_SIZE */
               + nla_total_size(1) /* IFLA_OPERSTATE */
               + nla_total_size(1) /* IFLA_LINKMODE */
               + nla_total_size(4) /* IFLA_CARRIER_CHANGES */
@@ -1605,7 +1609,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
                head = &net->dev_index_head[h];
                hlist_for_each_entry(dev, head, index_hlist) {
                        if (link_dump_filtered(dev, master_idx, kind_ops))
-                               continue;
+                               goto cont;
                        if (idx < s_idx)
                                goto cont;
                        err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
@@ -2733,7 +2737,7 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
                                                           ext_filter_mask));
        }
 
-       return min_ifinfo_dump_size;
+       return nlmsg_total_size(min_ifinfo_dump_size);
 }
 
 static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
@@ -2848,7 +2852,10 @@ nla_put_failure:
 
 static inline size_t rtnl_fdb_nlmsg_size(void)
 {
-       return NLMSG_ALIGN(sizeof(struct ndmsg)) + nla_total_size(ETH_ALEN);
+       return NLMSG_ALIGN(sizeof(struct ndmsg)) +
+              nla_total_size(ETH_ALEN) +       /* NDA_LLADDR */
+              nla_total_size(sizeof(u16)) +    /* NDA_VLAN */
+              0;
 }
 
 static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, u16 vid, int type,
index c73e28fc9c2a45225af39f7905072456d4380c7f..00a074dbfe9bf169c2b81498e6ae265199745b22 100644 (file)
@@ -453,7 +453,7 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 EXPORT_SYMBOL(sock_queue_rcv_skb);
 
 int __sk_receive_skb(struct sock *sk, struct sk_buff *skb,
-                    const int nested, unsigned int trim_cap)
+                    const int nested, unsigned int trim_cap, bool refcounted)
 {
        int rc = NET_RX_SUCCESS;
 
@@ -487,7 +487,8 @@ int __sk_receive_skb(struct sock *sk, struct sk_buff *skb,
 
        bh_unlock_sock(sk);
 out:
-       sock_put(sk);
+       if (refcounted)
+               sock_put(sk);
        return rc;
 discard_and_relse:
        kfree_skb(skb);
@@ -714,7 +715,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                val = min_t(u32, val, sysctl_wmem_max);
 set_sndbuf:
                sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
-               sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF);
+               sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF);
                /* Wake up sending tasks if we upped the value. */
                sk->sk_write_space(sk);
                break;
@@ -750,7 +751,7 @@ set_rcvbuf:
                 * returning the value we actually used in getsockopt
                 * is the most desirable behavior.
                 */
-               sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
+               sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF);
                break;
 
        case SO_RCVBUFFORCE:
@@ -1543,6 +1544,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
                RCU_INIT_POINTER(newsk->sk_reuseport_cb, NULL);
 
                newsk->sk_err      = 0;
+               newsk->sk_err_soft = 0;
                newsk->sk_priority = 0;
                newsk->sk_incoming_cpu = raw_smp_processor_id();
                atomic64_set(&newsk->sk_cookie, 0);
index e92b759d906c1bbcad5ff3ecc977d6393df90361..9a1a352fd1ebe598e4925bcda037dc0e4a2288bc 100644 (file)
@@ -129,7 +129,6 @@ int reuseport_add_sock(struct sock *sk, struct sock *sk2)
 
        return 0;
 }
-EXPORT_SYMBOL(reuseport_add_sock);
 
 static void reuseport_free_rcu(struct rcu_head *head)
 {
index 4f6c1862dfd25271303873acbc5c85b80b9f00c1..3202d75329b504b6442441becc31157e0c2be7a5 100644 (file)
@@ -1353,6 +1353,7 @@ static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
 dcb_unlock:
        spin_unlock_bh(&dcb_lock);
 nla_put_failure:
+       err = -EMSGSIZE;
        return err;
 }
 
index 345a3aeb8c7e36449a765298cd6512eab8cfef4b..edbe59d203efcff5b01978ff27c72756dc4ed6ba 100644 (file)
@@ -235,7 +235,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
 {
        const struct iphdr *iph = (struct iphdr *)skb->data;
        const u8 offset = iph->ihl << 2;
-       const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
+       const struct dccp_hdr *dh;
        struct dccp_sock *dp;
        struct inet_sock *inet;
        const int type = icmp_hdr(skb)->type;
@@ -245,11 +245,13 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
        int err;
        struct net *net = dev_net(skb->dev);
 
-       if (skb->len < offset + sizeof(*dh) ||
-           skb->len < offset + __dccp_basic_hdr_len(dh)) {
-               __ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
-               return;
-       }
+       /* Only need dccph_dport & dccph_sport which are the first
+        * 4 bytes in dccp header.
+        * Our caller (icmp_socket_deliver()) already pulled 8 bytes for us.
+        */
+       BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
+       BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
+       dh = (struct dccp_hdr *)(skb->data + offset);
 
        sk = __inet_lookup_established(net, &dccp_hashinfo,
                                       iph->daddr, dh->dccph_dport,
@@ -698,6 +700,7 @@ int dccp_invalid_packet(struct sk_buff *skb)
 {
        const struct dccp_hdr *dh;
        unsigned int cscov;
+       u8 dccph_doff;
 
        if (skb->pkt_type != PACKET_HOST)
                return 1;
@@ -719,18 +722,19 @@ int dccp_invalid_packet(struct sk_buff *skb)
        /*
         * If P.Data Offset is too small for packet type, drop packet and return
         */
-       if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
-               DCCP_WARN("P.Data Offset(%u) too small\n", dh->dccph_doff);
+       dccph_doff = dh->dccph_doff;
+       if (dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
+               DCCP_WARN("P.Data Offset(%u) too small\n", dccph_doff);
                return 1;
        }
        /*
         * If P.Data Offset is too too large for packet, drop packet and return
         */
-       if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) {
-               DCCP_WARN("P.Data Offset(%u) too large\n", dh->dccph_doff);
+       if (!pskb_may_pull(skb, dccph_doff * sizeof(u32))) {
+               DCCP_WARN("P.Data Offset(%u) too large\n", dccph_doff);
                return 1;
        }
-
+       dh = dccp_hdr(skb);
        /*
         * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet
         * has short sequence numbers), drop packet and return
@@ -868,7 +872,7 @@ lookup:
                goto discard_and_relse;
        nf_reset(skb);
 
-       return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4);
+       return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4, refcounted);
 
 no_dccp_socket:
        if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
index 3828f94b234c1104a3e745b3c0a76ab343aed4b6..715e5d1dc10720adbc912ec67aef11905eeb96a1 100644 (file)
@@ -70,7 +70,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                        u8 type, u8 code, int offset, __be32 info)
 {
        const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
-       const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
+       const struct dccp_hdr *dh;
        struct dccp_sock *dp;
        struct ipv6_pinfo *np;
        struct sock *sk;
@@ -78,12 +78,13 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        __u64 seq;
        struct net *net = dev_net(skb->dev);
 
-       if (skb->len < offset + sizeof(*dh) ||
-           skb->len < offset + __dccp_basic_hdr_len(dh)) {
-               __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
-                                 ICMP6_MIB_INERRORS);
-               return;
-       }
+       /* Only need dccph_dport & dccph_sport which are the first
+        * 4 bytes in dccp header.
+        * Our caller (icmpv6_notify()) already pulled 8 bytes for us.
+        */
+       BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
+       BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
+       dh = (struct dccp_hdr *)(skb->data + offset);
 
        sk = __inet6_lookup_established(net, &dccp_hashinfo,
                                        &hdr->daddr, dh->dccph_dport,
@@ -738,7 +739,8 @@ lookup:
        if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
 
-       return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4) ? -1 : 0;
+       return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
+                               refcounted) ? -1 : 0;
 
 no_dccp_socket:
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
@@ -956,6 +958,7 @@ static const struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
        .getsockopt        = ipv6_getsockopt,
        .addr2sockaddr     = inet6_csk_addr2sockaddr,
        .sockaddr_len      = sizeof(struct sockaddr_in6),
+       .bind_conflict     = inet6_csk_bind_conflict,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_ipv6_setsockopt,
        .compat_getsockopt = compat_ipv6_getsockopt,
index 41e65804ddf59651c78ae58b697e7e5e603c9167..9fe25bf6329691ecf0acdc35df7278b074d446c1 100644 (file)
@@ -1009,6 +1009,10 @@ void dccp_close(struct sock *sk, long timeout)
                __kfree_skb(skb);
        }
 
+       /* If socket has been already reset kill it. */
+       if (sk->sk_state == DCCP_CLOSED)
+               goto adjudge_to_death;
+
        if (data_was_unread) {
                /* Unread data was tossed, send an appropriate Reset Code */
                DCCP_WARN("ABORT with %u bytes unread\n", data_was_unread);
index a6902c1e2f28f79c609bf511de2781908e2e1abd..7899919cd9f0e3435828b1cca9e2ef897a75a3b7 100644 (file)
@@ -233,6 +233,8 @@ int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
                genphy_read_status(phydev);
                if (ds->ops->adjust_link)
                        ds->ops->adjust_link(ds, port, phydev);
+
+               put_device(&phydev->mdio.dev);
        }
 
        return 0;
@@ -504,15 +506,8 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
 
 void dsa_cpu_dsa_destroy(struct device_node *port_dn)
 {
-       struct phy_device *phydev;
-
-       if (of_phy_is_fixed_link(port_dn)) {
-               phydev = of_phy_find_device(port_dn);
-               if (phydev) {
-                       phy_device_free(phydev);
-                       fixed_phy_unregister(phydev);
-               }
-       }
+       if (of_phy_is_fixed_link(port_dn))
+               of_phy_deregister_fixed_link(port_dn);
 }
 
 static void dsa_switch_destroy(struct dsa_switch *ds)
index f8a7d9aab4372aed09dc9cd12baba0df1ce8f8ba..5fff951a0a4928ccf28fb681be86c7df6a05e94f 100644 (file)
@@ -28,8 +28,10 @@ static struct dsa_switch_tree *dsa_get_dst(u32 tree)
        struct dsa_switch_tree *dst;
 
        list_for_each_entry(dst, &dsa_switch_trees, list)
-               if (dst->tree == tree)
+               if (dst->tree == tree) {
+                       kref_get(&dst->refcount);
                        return dst;
+               }
        return NULL;
 }
 
index 6b1282c006b145d2b96921243b9e26e91c427f88..30e2e21d76196fdfc404ab036a3e6efb9905d3b8 100644 (file)
@@ -1125,7 +1125,7 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
        p->phy_interface = mode;
 
        phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
-       if (of_phy_is_fixed_link(port_dn)) {
+       if (!phy_dn && of_phy_is_fixed_link(port_dn)) {
                /* In the case of a fixed PHY, the DT node associated
                 * to the fixed PHY is the Port DT node
                 */
@@ -1135,7 +1135,7 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
                        return ret;
                }
                phy_is_fixed = true;
-               phy_dn = port_dn;
+               phy_dn = of_node_get(port_dn);
        }
 
        if (ds->ops->get_phy_flags)
@@ -1154,6 +1154,7 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
                        ret = dsa_slave_phy_connect(p, slave_dev, phy_id);
                        if (ret) {
                                netdev_err(slave_dev, "failed to connect to phy%d: %d\n", phy_id, ret);
+                               of_node_put(phy_dn);
                                return ret;
                        }
                } else {
@@ -1162,6 +1163,8 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
                                                phy_flags,
                                                p->phy_interface);
                }
+
+               of_node_put(phy_dn);
        }
 
        if (p->phy && phy_is_fixed)
@@ -1174,6 +1177,8 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
                ret = dsa_slave_phy_connect(p, slave_dev, p->port);
                if (ret) {
                        netdev_err(slave_dev, "failed to connect to port %d: %d\n", p->port, ret);
+                       if (phy_is_fixed)
+                               of_phy_deregister_fixed_link(port_dn);
                        return ret;
                }
        }
@@ -1289,10 +1294,18 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 void dsa_slave_destroy(struct net_device *slave_dev)
 {
        struct dsa_slave_priv *p = netdev_priv(slave_dev);
+       struct dsa_switch *ds = p->parent;
+       struct device_node *port_dn;
+
+       port_dn = ds->ports[p->port].dn;
 
        netif_carrier_off(slave_dev);
-       if (p->phy)
+       if (p->phy) {
                phy_disconnect(p->phy);
+
+               if (of_phy_is_fixed_link(port_dn))
+                       of_phy_deregister_fixed_link(port_dn);
+       }
        unregister_netdev(slave_dev);
        free_netdev(slave_dev);
 }
index 66dff5e3d7728bc9d302fdf6c207a6c03197affa..02acfff36028bfc3260d7568881bb412be312d27 100644 (file)
@@ -439,7 +439,7 @@ struct sk_buff **eth_gro_receive(struct sk_buff **head,
 
        skb_gro_pull(skb, sizeof(*eh));
        skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
-       pp = ptype->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 
 out_unlock:
        rcu_read_unlock();
index 5ee1d43f13100849c6ac28a75082d65f69350d72..4ebe2aa3e7d3e944295e9d53890e3cb9b7a90139 100644 (file)
@@ -300,10 +300,6 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
 static void check_local_dest(struct hsr_priv *hsr, struct sk_buff *skb,
                             struct hsr_frame_info *frame)
 {
-       struct net_device *master_dev;
-
-       master_dev = hsr_port_get_hsr(hsr, HSR_PT_MASTER)->dev;
-
        if (hsr_addr_is_self(hsr, eth_hdr(skb)->h_dest)) {
                frame->is_local_exclusive = true;
                skb->pkt_type = PACKET_HOST;
index 300b06888fdfd0139eddf202b1d4ef9ee90c1f76..b54b3ca939db3984e8c5f839d8f56f01e60dea9f 100644 (file)
@@ -715,6 +715,7 @@ config DEFAULT_TCP_CONG
        default "reno" if DEFAULT_RENO
        default "dctcp" if DEFAULT_DCTCP
        default "cdg" if DEFAULT_CDG
+       default "bbr" if DEFAULT_BBR
        default "cubic"
 
 config TCP_MD5SIG
index 1effc986739e5d068c7ee04f614ec3f0845c408e..215143246e4b3e57440aba0fd314d0e96acd22a7 100644 (file)
@@ -533,9 +533,9 @@ EXPORT_SYMBOL(inet_dgram_connect);
 
 static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
 {
-       DEFINE_WAIT(wait);
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
-       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+       add_wait_queue(sk_sleep(sk), &wait);
        sk->sk_write_pending += writebias;
 
        /* Basic assumption: if someone sets sk->sk_err, he _must_
@@ -545,13 +545,12 @@ static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
         */
        while ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
                release_sock(sk);
-               timeo = schedule_timeout(timeo);
+               timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
                lock_sock(sk);
                if (signal_pending(current) || !timeo)
                        break;
-               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk_sleep(sk), &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
        sk->sk_write_pending -= writebias;
        return timeo;
 }
@@ -1234,7 +1233,7 @@ struct sk_buff *inet_gso_segment(struct sk_buff *skb,
                fixedid = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID);
 
                /* fixed ID is invalid if DF bit is not set */
-               if (fixedid && !(iph->frag_off & htons(IP_DF)))
+               if (fixedid && !(ip_hdr(skb)->frag_off & htons(IP_DF)))
                        goto out;
        }
 
@@ -1391,7 +1390,7 @@ struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff *skb)
        skb_gro_pull(skb, sizeof(*iph));
        skb_set_transport_header(skb, skb_gro_offset(skb));
 
-       pp = ops->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
 
 out_unlock:
        rcu_read_unlock();
index d95631d0924899f17549e69801567bed076491b9..20fb25e3027bbbf8b8c2068751caf40df939546d 100644 (file)
@@ -476,7 +476,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
                esph = (void *)skb_push(skb, 4);
                *seqhi = esph->spi;
                esph->spi = esph->seq_no;
-               esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.input.hi);
+               esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi;
                aead_request_set_callback(req, 0, esp_input_done_esn, skb);
        }
 
index c3b80478226ed4aab6ed8ce1e75ea34c9a921385..161fc0f0d752fb559918c22c5c87e7ef7c84dbe6 100644 (file)
@@ -151,7 +151,7 @@ static void fib_replace_table(struct net *net, struct fib_table *old,
 
 int fib_unmerge(struct net *net)
 {
-       struct fib_table *old, *new;
+       struct fib_table *old, *new, *main_table;
 
        /* attempt to fetch local table if it has been allocated */
        old = fib_get_table(net, RT_TABLE_LOCAL);
@@ -162,11 +162,21 @@ int fib_unmerge(struct net *net)
        if (!new)
                return -ENOMEM;
 
+       /* table is already unmerged */
+       if (new == old)
+               return 0;
+
        /* replace merged table with clean table */
-       if (new != old) {
-               fib_replace_table(net, old, new);
-               fib_free_table(old);
-       }
+       fib_replace_table(net, old, new);
+       fib_free_table(old);
+
+       /* attempt to fetch main table if it has been allocated */
+       main_table = fib_get_table(net, RT_TABLE_MAIN);
+       if (!main_table)
+               return 0;
+
+       /* flush local entries from main table */
+       fib_table_flush_external(main_table);
 
        return 0;
 }
index 31cef3602585b50e463b017cff2837f7bdd0dfb0..e3665bf7a7f373cfb2cea7a57a9ba478b9cf11df 100644 (file)
@@ -719,6 +719,13 @@ static unsigned char update_suffix(struct key_vector *tn)
 {
        unsigned char slen = tn->pos;
        unsigned long stride, i;
+       unsigned char slen_max;
+
+       /* only vector 0 can have a suffix length greater than or equal to
+        * tn->pos + tn->bits, the second highest node will have a suffix
+        * length at most of tn->pos + tn->bits - 1
+        */
+       slen_max = min_t(unsigned char, tn->pos + tn->bits - 1, tn->slen);
 
        /* search though the list of children looking for nodes that might
         * have a suffix greater than the one we currently have.  This is
@@ -736,12 +743,8 @@ static unsigned char update_suffix(struct key_vector *tn)
                slen = n->slen;
                i &= ~(stride - 1);
 
-               /* if slen covers all but the last bit we can stop here
-                * there will be nothing longer than that since only node
-                * 0 and 1 << (bits - 1) could have that as their suffix
-                * length.
-                */
-               if ((slen + 1) >= (tn->pos + tn->bits))
+               /* stop searching if we have hit the maximum possible value */
+               if (slen >= slen_max)
                        break;
        }
 
@@ -913,39 +916,27 @@ static struct key_vector *resize(struct trie *t, struct key_vector *tn)
                return collapse(t, tn);
 
        /* update parent in case halve failed */
-       tp = node_parent(tn);
-
-       /* Return if at least one deflate was run */
-       if (max_work != MAX_WORK)
-               return tp;
-
-       /* push the suffix length to the parent node */
-       if (tn->slen > tn->pos) {
-               unsigned char slen = update_suffix(tn);
-
-               if (slen > tp->slen)
-                       tp->slen = slen;
-       }
-
-       return tp;
+       return node_parent(tn);
 }
 
-static void leaf_pull_suffix(struct key_vector *tp, struct key_vector *l)
+static void node_pull_suffix(struct key_vector *tn, unsigned char slen)
 {
-       while ((tp->slen > tp->pos) && (tp->slen > l->slen)) {
-               if (update_suffix(tp) > l->slen)
+       unsigned char node_slen = tn->slen;
+
+       while ((node_slen > tn->pos) && (node_slen > slen)) {
+               slen = update_suffix(tn);
+               if (node_slen == slen)
                        break;
-               tp = node_parent(tp);
+
+               tn = node_parent(tn);
+               node_slen = tn->slen;
        }
 }
 
-static void leaf_push_suffix(struct key_vector *tn, struct key_vector *l)
+static void node_push_suffix(struct key_vector *tn, unsigned char slen)
 {
-       /* if this is a new leaf then tn will be NULL and we can sort
-        * out parent suffix lengths as a part of trie_rebalance
-        */
-       while (tn->slen < l->slen) {
-               tn->slen = l->slen;
+       while (tn->slen < slen) {
+               tn->slen = slen;
                tn = node_parent(tn);
        }
 }
@@ -1066,6 +1057,7 @@ static int fib_insert_node(struct trie *t, struct key_vector *tp,
        }
 
        /* Case 3: n is NULL, and will just insert a new leaf */
+       node_push_suffix(tp, new->fa_slen);
        NODE_INIT_PARENT(l, tp);
        put_child_root(tp, key, l);
        trie_rebalance(t, tp);
@@ -1107,7 +1099,7 @@ static int fib_insert_alias(struct trie *t, struct key_vector *tp,
        /* if we added to the tail node then we need to update slen */
        if (l->slen < new->fa_slen) {
                l->slen = new->fa_slen;
-               leaf_push_suffix(tp, l);
+               node_push_suffix(tp, new->fa_slen);
        }
 
        return 0;
@@ -1499,6 +1491,8 @@ static void fib_remove_alias(struct trie *t, struct key_vector *tp,
         * out parent suffix lengths as a part of trie_rebalance
         */
        if (hlist_empty(&l->leaf)) {
+               if (tp->slen == l->slen)
+                       node_pull_suffix(tp, tp->pos);
                put_child_root(tp, l->key, NULL);
                node_free(l);
                trie_rebalance(t, tp);
@@ -1511,7 +1505,7 @@ static void fib_remove_alias(struct trie *t, struct key_vector *tp,
 
        /* update the trie with the latest suffix length */
        l->slen = fa->fa_slen;
-       leaf_pull_suffix(tp, l);
+       node_pull_suffix(tp, fa->fa_slen);
 }
 
 /* Caller must hold RTNL. */
@@ -1743,8 +1737,10 @@ struct fib_table *fib_trie_unmerge(struct fib_table *oldtb)
                                local_l = fib_find_node(lt, &local_tp, l->key);
 
                        if (fib_insert_alias(lt, local_tp, local_l, new_fa,
-                                            NULL, l->key))
+                                            NULL, l->key)) {
+                               kmem_cache_free(fn_alias_kmem, new_fa);
                                goto out;
+                       }
                }
 
                /* stop loop if key wrapped back to 0 */
@@ -1760,6 +1756,75 @@ out:
        return NULL;
 }
 
+/* Caller must hold RTNL */
+void fib_table_flush_external(struct fib_table *tb)
+{
+       struct trie *t = (struct trie *)tb->tb_data;
+       struct key_vector *pn = t->kv;
+       unsigned long cindex = 1;
+       struct hlist_node *tmp;
+       struct fib_alias *fa;
+
+       /* walk trie in reverse order */
+       for (;;) {
+               unsigned char slen = 0;
+               struct key_vector *n;
+
+               if (!(cindex--)) {
+                       t_key pkey = pn->key;
+
+                       /* cannot resize the trie vector */
+                       if (IS_TRIE(pn))
+                               break;
+
+                       /* update the suffix to address pulled leaves */
+                       if (pn->slen > pn->pos)
+                               update_suffix(pn);
+
+                       /* resize completed node */
+                       pn = resize(t, pn);
+                       cindex = get_index(pkey, pn);
+
+                       continue;
+               }
+
+               /* grab the next available node */
+               n = get_child(pn, cindex);
+               if (!n)
+                       continue;
+
+               if (IS_TNODE(n)) {
+                       /* record pn and cindex for leaf walking */
+                       pn = n;
+                       cindex = 1ul << n->bits;
+
+                       continue;
+               }
+
+               hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) {
+                       /* if alias was cloned to local then we just
+                        * need to remove the local copy from main
+                        */
+                       if (tb->tb_id != fa->tb_id) {
+                               hlist_del_rcu(&fa->fa_list);
+                               alias_free_mem_rcu(fa);
+                               continue;
+                       }
+
+                       /* record local slen */
+                       slen = fa->fa_slen;
+               }
+
+               /* update leaf slen */
+               n->slen = slen;
+
+               if (hlist_empty(&n->leaf)) {
+                       put_child_root(pn, n->key, NULL);
+                       node_free(n);
+               }
+       }
+}
+
 /* Caller must hold RTNL. */
 int fib_table_flush(struct net *net, struct fib_table *tb)
 {
@@ -1782,6 +1847,10 @@ int fib_table_flush(struct net *net, struct fib_table *tb)
                        if (IS_TRIE(pn))
                                break;
 
+                       /* update the suffix to address pulled leaves */
+                       if (pn->slen > pn->pos)
+                               update_suffix(pn);
+
                        /* resize completed node */
                        pn = resize(t, pn);
                        cindex = get_index(pkey, pn);
@@ -2413,22 +2482,19 @@ static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter,
        struct key_vector *l, **tp = &iter->tnode;
        t_key key;
 
-       /* use cache location of next-to-find key */
+       /* use cached location of previously found key */
        if (iter->pos > 0 && pos >= iter->pos) {
-               pos -= iter->pos;
                key = iter->key;
        } else {
-               iter->pos = 0;
+               iter->pos = 1;
                key = 0;
        }
 
-       while ((l = leaf_walk_rcu(tp, key)) != NULL) {
+       pos -= iter->pos;
+
+       while ((l = leaf_walk_rcu(tp, key)) && (pos-- > 0)) {
                key = l->key + 1;
                iter->pos++;
-
-               if (--pos <= 0)
-                       break;
-
                l = NULL;
 
                /* handle unlikely case of a key wrap */
@@ -2437,7 +2503,7 @@ static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter,
        }
 
        if (l)
-               iter->key = key;        /* remember it */
+               iter->key = l->key;     /* remember it */
        else
                iter->pos = 0;          /* forget it */
 
@@ -2465,7 +2531,7 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
                return fib_route_get_idx(iter, *pos);
 
        iter->pos = 0;
-       iter->key = 0;
+       iter->key = KEY_MAX;
 
        return SEQ_START_TOKEN;
 }
@@ -2474,7 +2540,7 @@ static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct fib_route_iter *iter = seq->private;
        struct key_vector *l = NULL;
-       t_key key = iter->key;
+       t_key key = iter->key + 1;
 
        ++*pos;
 
@@ -2483,7 +2549,7 @@ static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                l = leaf_walk_rcu(&iter->tnode, key);
 
        if (l) {
-               iter->key = l->key + 1;
+               iter->key = l->key;
                iter->pos++;
        } else {
                iter->pos = 0;
index cf50f7e2b0124d3bfa6ad2caae65cf1cf590ad44..030d1531e897a14c44d6dbf04dc21df2c87da399 100644 (file)
@@ -249,7 +249,7 @@ static struct sk_buff **fou_gro_receive(struct sock *sk,
        if (!ops || !ops->callbacks.gro_receive)
                goto out_unlock;
 
-       pp = ops->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
 
 out_unlock:
        rcu_read_unlock();
@@ -441,7 +441,7 @@ next_proto:
        if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
                goto out_unlock;
 
-       pp = ops->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
        flush = 0;
 
 out_unlock:
index 96e0efecefa6aa2f4bc97c098c08ee6c25f2e11c..d5cac99170b194151b16f614508f7fa0933ff2e1 100644 (file)
@@ -229,7 +229,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
        /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
        skb_gro_postpull_rcsum(skb, greh, grehlen);
 
-       pp = ptype->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
        flush = 0;
 
 out_unlock:
index 38abe70e595fabf472aa8fe094e71d070f781164..48734ee6293f3383e064ba18734abc485b1c3639 100644 (file)
@@ -477,7 +477,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
        fl4->flowi4_proto = IPPROTO_ICMP;
        fl4->fl4_icmp_type = type;
        fl4->fl4_icmp_code = code;
-       fl4->flowi4_oif = l3mdev_master_ifindex(skb_in->dev);
+       fl4->flowi4_oif = l3mdev_master_ifindex(skb_dst(skb_in)->dev);
 
        security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
        rt = __ip_route_output_key_hash(net, fl4,
@@ -502,7 +502,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
        if (err)
                goto relookup_failed;
 
-       if (inet_addr_type_dev_table(net, skb_in->dev,
+       if (inet_addr_type_dev_table(net, skb_dst(skb_in)->dev,
                                     fl4_dec.saddr) == RTN_LOCAL) {
                rt2 = __ip_route_output_key(net, &fl4_dec);
                if (IS_ERR(rt2))
index 606cc3e85d2bc7b1fc02e5c2ea305a5bd65349c5..15db786d50ed28c7d31855a9582ab111752b3641 100644 (file)
@@ -162,7 +162,7 @@ static int unsolicited_report_interval(struct in_device *in_dev)
 }
 
 static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
-static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr);
+static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im);
 static void igmpv3_clear_delrec(struct in_device *in_dev);
 static int sf_setstate(struct ip_mc_list *pmc);
 static void sf_markstate(struct ip_mc_list *pmc);
@@ -1130,10 +1130,15 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
        spin_unlock_bh(&in_dev->mc_tomb_lock);
 }
 
-static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
+/*
+ * restore ip_mc_list deleted records
+ */
+static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
 {
        struct ip_mc_list *pmc, *pmc_prev;
-       struct ip_sf_list *psf, *psf_next;
+       struct ip_sf_list *psf;
+       struct net *net = dev_net(in_dev->dev);
+       __be32 multiaddr = im->multiaddr;
 
        spin_lock_bh(&in_dev->mc_tomb_lock);
        pmc_prev = NULL;
@@ -1149,16 +1154,26 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
                        in_dev->mc_tomb = pmc->next;
        }
        spin_unlock_bh(&in_dev->mc_tomb_lock);
+
+       spin_lock_bh(&im->lock);
        if (pmc) {
-               for (psf = pmc->tomb; psf; psf = psf_next) {
-                       psf_next = psf->sf_next;
-                       kfree(psf);
+               im->interface = pmc->interface;
+               im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+               im->sfmode = pmc->sfmode;
+               if (pmc->sfmode == MCAST_INCLUDE) {
+                       im->tomb = pmc->tomb;
+                       im->sources = pmc->sources;
+                       for (psf = im->sources; psf; psf = psf->sf_next)
+                               psf->sf_crcount = im->crcount;
                }
                in_dev_put(pmc->interface);
-               kfree(pmc);
        }
+       spin_unlock_bh(&im->lock);
 }
 
+/*
+ * flush ip_mc_list deleted records
+ */
 static void igmpv3_clear_delrec(struct in_device *in_dev)
 {
        struct ip_mc_list *pmc, *nextpmc;
@@ -1366,7 +1381,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
        ip_mc_hash_add(in_dev, im);
 
 #ifdef CONFIG_IP_MULTICAST
-       igmpv3_del_delrec(in_dev, im->multiaddr);
+       igmpv3_del_delrec(in_dev, im);
 #endif
        igmp_group_added(im);
        if (!in_dev->dead)
@@ -1626,8 +1641,12 @@ void ip_mc_remap(struct in_device *in_dev)
 
        ASSERT_RTNL();
 
-       for_each_pmc_rtnl(in_dev, pmc)
+       for_each_pmc_rtnl(in_dev, pmc) {
+#ifdef CONFIG_IP_MULTICAST
+               igmpv3_del_delrec(in_dev, pmc);
+#endif
                igmp_group_added(pmc);
+       }
 }
 
 /* Device going down */
@@ -1648,7 +1667,6 @@ void ip_mc_down(struct in_device *in_dev)
        in_dev->mr_gq_running = 0;
        if (del_timer(&in_dev->mr_gq_timer))
                __in_dev_put(in_dev);
-       igmpv3_clear_delrec(in_dev);
 #endif
 
        ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
@@ -1688,8 +1706,12 @@ void ip_mc_up(struct in_device *in_dev)
 #endif
        ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
-       for_each_pmc_rtnl(in_dev, pmc)
+       for_each_pmc_rtnl(in_dev, pmc) {
+#ifdef CONFIG_IP_MULTICAST
+               igmpv3_del_delrec(in_dev, pmc);
+#endif
                igmp_group_added(pmc);
+       }
 }
 
 /*
@@ -1704,13 +1726,13 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
 
        /* Deactivate timers */
        ip_mc_down(in_dev);
+#ifdef CONFIG_IP_MULTICAST
+       igmpv3_clear_delrec(in_dev);
+#endif
 
        while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) {
                in_dev->mc_list = i->next_rcu;
                in_dev->mc_count--;
-
-               /* We've dropped the groups in ip_mc_down already */
-               ip_mc_clear_src(i);
                ip_ma_put(i);
        }
 }
index 77c20a489218c9cf1865f397b83f43bc58457dc6..ca97835bfec4b2291446a54d7f6bb1af408afc29 100644 (file)
@@ -25,6 +25,7 @@
 #include <net/inet_hashtables.h>
 #include <net/secure_seq.h>
 #include <net/ip.h>
+#include <net/tcp.h>
 #include <net/sock_reuseport.h>
 
 static u32 inet_ehashfn(const struct net *net, const __be32 laddr,
@@ -172,7 +173,7 @@ EXPORT_SYMBOL_GPL(__inet_inherit_port);
 
 static inline int compute_score(struct sock *sk, struct net *net,
                                const unsigned short hnum, const __be32 daddr,
-                               const int dif)
+                               const int dif, bool exact_dif)
 {
        int score = -1;
        struct inet_sock *inet = inet_sk(sk);
@@ -186,7 +187,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
                                return -1;
                        score += 4;
                }
-               if (sk->sk_bound_dev_if) {
+               if (sk->sk_bound_dev_if || exact_dif) {
                        if (sk->sk_bound_dev_if != dif)
                                return -1;
                        score += 4;
@@ -215,11 +216,12 @@ struct sock *__inet_lookup_listener(struct net *net,
        unsigned int hash = inet_lhashfn(net, hnum);
        struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
        int score, hiscore = 0, matches = 0, reuseport = 0;
+       bool exact_dif = inet_exact_dif_match(net, skb);
        struct sock *sk, *result = NULL;
        u32 phash = 0;
 
        sk_for_each_rcu(sk, &ilb->head) {
-               score = compute_score(sk, net, hnum, daddr, dif);
+               score = compute_score(sk, net, hnum, daddr, dif, exact_dif);
                if (score > hiscore) {
                        reuseport = sk->sk_reuseport;
                        if (reuseport) {
index 8b4ffd2168395b4d3b6ec67e166af13c122128ca..9f0a7b96646f368021d9cd51bc3f728ba49eed0d 100644 (file)
@@ -117,7 +117,7 @@ int ip_forward(struct sk_buff *skb)
        if (opt->is_strictroute && rt->rt_uses_gateway)
                goto sr_failed;
 
-       IPCB(skb)->flags |= IPSKB_FORWARDED | IPSKB_FRAG_SEGS;
+       IPCB(skb)->flags |= IPSKB_FORWARDED;
        mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
        if (ip_exceeds_mtu(skb, mtu)) {
                IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
index 05d105832bdbb88f5f9d611d9f8bd35b1ae7f5d6..877bdb02e887f5cf7ce1c4610123484a22f89310 100644 (file)
@@ -107,6 +107,8 @@ int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
        if (unlikely(!skb))
                return 0;
 
+       skb->protocol = htons(ETH_P_IP);
+
        return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT,
                       net, sk, skb, NULL, skb_dst(skb)->dev,
                       dst_output);
@@ -239,19 +241,23 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk,
        struct sk_buff *segs;
        int ret = 0;
 
-       /* common case: fragmentation of segments is not allowed,
-        * or seglen is <= mtu
+       /* common case: seglen is <= mtu
         */
-       if (((IPCB(skb)->flags & IPSKB_FRAG_SEGS) == 0) ||
-             skb_gso_validate_mtu(skb, mtu))
+       if (skb_gso_validate_mtu(skb, mtu))
                return ip_finish_output2(net, sk, skb);
 
-       /* Slowpath -  GSO segment length is exceeding the dst MTU.
+       /* Slowpath -  GSO segment length exceeds the egress MTU.
         *
-        * This can happen in two cases:
-        * 1) TCP GRO packet, DF bit not set
-        * 2) skb arrived via virtio-net, we thus get TSO/GSO skbs directly
-        * from host network stack.
+        * This can happen in several cases:
+        *  - Forwarding of a TCP GRO skb, when DF flag is not set.
+        *  - Forwarding of an skb that arrived on a virtualization interface
+        *    (virtio-net/vhost/tap) with TSO/GSO size set by other network
+        *    stack.
+        *  - Local GSO skb transmitted on an NETIF_F_TSO tunnel stacked over an
+        *    interface with a smaller MTU.
+        *  - Arriving GRO skb (or GSO skb in a virtualized environment) that is
+        *    bridged to a NETIF_F_TSO tunnel stacked over an interface with an
+        *    insufficent MTU.
         */
        features = netif_skb_features(skb);
        BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
@@ -538,7 +544,6 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
 {
        struct iphdr *iph;
        int ptr;
-       struct net_device *dev;
        struct sk_buff *skb2;
        unsigned int mtu, hlen, left, len, ll_rs;
        int offset;
@@ -546,8 +551,6 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
        struct rtable *rt = skb_rtable(skb);
        int err = 0;
 
-       dev = rt->dst.dev;
-
        /* for offloaded checksums cleanup checksum before fragmentation */
        if (skb->ip_summed == CHECKSUM_PARTIAL &&
            (err = skb_checksum_help(skb)))
@@ -1582,7 +1585,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
        }
 
        oif = arg->bound_dev_if;
-       oif = oif ? : skb->skb_iif;
+       if (!oif && netif_index_is_l3_master(net, skb->skb_iif))
+               oif = skb->skb_iif;
 
        flowi4_init_output(&fl4, oif,
                           IP4_REPLY_MARK(net, skb->mark),
index af4919792b6a812041dcb18ff30aa8b27482c7a2..b8a2d63d1fb82f5084a0d98911b8110816dee963 100644 (file)
@@ -98,7 +98,7 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
 }
 
 static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
-                                 int offset)
+                                 int tlen, int offset)
 {
        __wsum csum = skb->csum;
 
@@ -106,8 +106,9 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
                return;
 
        if (offset != 0)
-               csum = csum_sub(csum, csum_partial(skb_transport_header(skb),
-                                                  offset, 0));
+               csum = csum_sub(csum,
+                               csum_partial(skb_transport_header(skb) + tlen,
+                                            offset, 0));
 
        put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
 }
@@ -153,7 +154,7 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
 }
 
 void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
-                        int offset)
+                        int tlen, int offset)
 {
        struct inet_sock *inet = inet_sk(skb->sk);
        unsigned int flags = inet->cmsg_flags;
@@ -216,7 +217,7 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
        }
 
        if (flags & IP_CMSG_CHECKSUM)
-               ip_cmsg_recv_checksum(msg, skb, offset);
+               ip_cmsg_recv_checksum(msg, skb, tlen, offset);
 }
 EXPORT_SYMBOL(ip_cmsg_recv_offset);
 
index 777bc1883870ec91d7c4df9adfde50fc3f384043..fed3d29f9eb3b716664b8d9eba052695cbb867bd 100644 (file)
@@ -63,7 +63,6 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
        int pkt_len = skb->len - skb_inner_network_offset(skb);
        struct net *net = dev_net(rt->dst.dev);
        struct net_device *dev = skb->dev;
-       int skb_iif = skb->skb_iif;
        struct iphdr *iph;
        int err;
 
@@ -73,16 +72,6 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
        skb_dst_set(skb, &rt->dst);
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
 
-       if (skb_iif && !(df & htons(IP_DF))) {
-               /* Arrived from an ingress interface, got encapsulated, with
-                * fragmentation of encapulating frames allowed.
-                * If skb is gso, the resulting encapsulated network segments
-                * may exceed dst mtu.
-                * Allow IP Fragmentation of segments.
-                */
-               IPCB(skb)->flags |= IPSKB_FRAG_SEGS;
-       }
-
        /* Push down and install the IP header. */
        skb_push(skb, sizeof(struct iphdr));
        skb_reset_network_header(skb);
index 5f006e13de567ad65ce856a47c118f5ea91ac671..27089f5ebbb1c1c6e13038a94aeee5209e03d532 100644 (file)
@@ -1749,7 +1749,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
                vif->dev->stats.tx_bytes += skb->len;
        }
 
-       IPCB(skb)->flags |= IPSKB_FORWARDED | IPSKB_FRAG_SEGS;
+       IPCB(skb)->flags |= IPSKB_FORWARDED;
 
        /* RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
         * not only before forwarding, but after forwarding on all output
index c3776ff6749f18d1bf3c5c5084d3e7656291539d..b3cc1335adbc1a20dcd225d0501b0a286d27e3c8 100644 (file)
@@ -24,10 +24,11 @@ int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned int addr_t
        struct flowi4 fl4 = {};
        __be32 saddr = iph->saddr;
        __u8 flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0;
+       struct net_device *dev = skb_dst(skb)->dev;
        unsigned int hh_len;
 
        if (addr_type == RTN_UNSPEC)
-               addr_type = inet_addr_type(net, saddr);
+               addr_type = inet_addr_type_dev_table(net, dev, saddr);
        if (addr_type == RTN_LOCAL || addr_type == RTN_UNICAST)
                flags |= FLOWI_FLAG_ANYSRC;
        else
@@ -40,6 +41,8 @@ int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned int addr_t
        fl4.saddr = saddr;
        fl4.flowi4_tos = RT_TOS(iph->tos);
        fl4.flowi4_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
+       if (!fl4.flowi4_oif)
+               fl4.flowi4_oif = l3mdev_master_ifindex(dev);
        fl4.flowi4_mark = skb->mark;
        fl4.flowi4_flags = flags;
        rt = ip_route_output_key(net, &fl4);
index b31df597fd37e4e8fa41777d7883973a6c852254..697538464e6e31f237d4a909174fe6a5fb267367 100644 (file)
@@ -1201,8 +1201,8 @@ static int translate_compat_table(struct xt_table_info **pinfo,
 
        newinfo->number = compatr->num_entries;
        for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
-               newinfo->hook_entry[i] = info->hook_entry[i];
-               newinfo->underflow[i] = info->underflow[i];
+               newinfo->hook_entry[i] = compatr->hook_entry[i];
+               newinfo->underflow[i] = compatr->underflow[i];
        }
        entry1 = newinfo->entries;
        pos = entry1;
index bf855e64fc45c86fbf286bc34b2bd96fbac17cff..0c01a270bf9fb0a0a8d57a80633a78133e668c01 100644 (file)
@@ -28,7 +28,7 @@ static void nft_dup_ipv4_eval(const struct nft_expr *expr,
        struct in_addr gw = {
                .s_addr = (__force __be32)regs->data[priv->sreg_addr],
        };
-       int oif = regs->data[priv->sreg_dev];
+       int oif = priv->sreg_dev ? regs->data[priv->sreg_dev] : -1;
 
        nf_dup_ipv4(pkt->net, pkt->skb, pkt->hook, &gw, oif);
 }
@@ -59,7 +59,9 @@ static int nft_dup_ipv4_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        struct nft_dup_ipv4 *priv = nft_expr_priv(expr);
 
-       if (nft_dump_register(skb, NFTA_DUP_SREG_ADDR, priv->sreg_addr) ||
+       if (nft_dump_register(skb, NFTA_DUP_SREG_ADDR, priv->sreg_addr))
+               goto nla_put_failure;
+       if (priv->sreg_dev &&
            nft_dump_register(skb, NFTA_DUP_SREG_DEV, priv->sreg_dev))
                goto nla_put_failure;
 
index 7cf7d6e380c2c87ecccb11bae3f677676062d11f..96b8e2b957313d36c0c6d339fb21754d71d691ea 100644 (file)
@@ -657,6 +657,10 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
        if (len > 0xFFFF)
                return -EMSGSIZE;
 
+       /* Must have at least a full ICMP header. */
+       if (len < icmph_len)
+               return -EINVAL;
+
        /*
         *      Check the flags.
         */
@@ -994,7 +998,7 @@ struct proto ping_prot = {
        .init =         ping_init_sock,
        .close =        ping_close,
        .connect =      ip4_datagram_connect,
-       .disconnect =   udp_disconnect,
+       .disconnect =   __udp_disconnect,
        .setsockopt =   ip_setsockopt,
        .getsockopt =   ip_getsockopt,
        .sendmsg =      ping_v4_sendmsg,
index 90a85c95587244545fd41a9a191691166a9f1815..ecbe5a7c2d6d3fb6a55e4c8464eab4853f4fe909 100644 (file)
@@ -918,7 +918,7 @@ struct proto raw_prot = {
        .close             = raw_close,
        .destroy           = raw_destroy,
        .connect           = ip4_datagram_connect,
-       .disconnect        = udp_disconnect,
+       .disconnect        = __udp_disconnect,
        .ioctl             = raw_ioctl,
        .init              = raw_init,
        .setsockopt        = raw_setsockopt,
index 62d4d90c1389c4ea7da37c81779b2f55207d2a92..2a57566e6e91947d459ae8908374539b83fc3a9d 100644 (file)
@@ -753,7 +753,9 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
                        goto reject_redirect;
        }
 
-       n = ipv4_neigh_lookup(&rt->dst, NULL, &new_gw);
+       n = __ipv4_neigh_lookup(rt->dst.dev, new_gw);
+       if (!n)
+               n = neigh_create(&arp_tbl, &new_gw, rt->dst.dev);
        if (!IS_ERR(n)) {
                if (!(n->nud_state & NUD_VALID)) {
                        neigh_event_send(n, NULL);
index 1cb67de106fee1103aa487af1f889ae6aea0c80c..80bc36b25de21d5e6b1c3e6f6001258b38656d41 100644 (file)
@@ -96,11 +96,11 @@ static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low
                container_of(table->data, struct net, ipv4.ping_group_range.range);
        unsigned int seq;
        do {
-               seq = read_seqbegin(&net->ipv4.ip_local_ports.lock);
+               seq = read_seqbegin(&net->ipv4.ping_group_range.lock);
 
                *low = data[0];
                *high = data[1];
-       } while (read_seqretry(&net->ipv4.ip_local_ports.lock, seq));
+       } while (read_seqretry(&net->ipv4.ping_group_range.lock, seq));
 }
 
 /* Update system visible IP port range */
@@ -109,10 +109,10 @@ static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t hig
        kgid_t *data = table->data;
        struct net *net =
                container_of(table->data, struct net, ipv4.ping_group_range.range);
-       write_seqlock(&net->ipv4.ip_local_ports.lock);
+       write_seqlock(&net->ipv4.ping_group_range.lock);
        data[0] = low;
        data[1] = high;
-       write_sequnlock(&net->ipv4.ip_local_ports.lock);
+       write_sequnlock(&net->ipv4.ping_group_range.lock);
 }
 
 /* Validate changes from /proc interface. */
index 3251fe71f39f2395befb0e662ca19423e6b9ea90..814af89c1bd3418130e0ad90def6623ca13a6d16 100644 (file)
@@ -1164,7 +1164,7 @@ restart:
 
        err = -EPIPE;
        if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
-               goto out_err;
+               goto do_error;
 
        sg = !!(sk->sk_route_caps & NETIF_F_SG);
 
@@ -1241,7 +1241,7 @@ new_segment:
 
                        if (!skb_can_coalesce(skb, i, pfrag->page,
                                              pfrag->offset)) {
-                               if (i == sysctl_max_skb_frags || !sg) {
+                               if (i >= sysctl_max_skb_frags || !sg) {
                                        tcp_mark_push(tp, skb);
                                        goto new_segment;
                                }
index 1294af4e0127b7a9b98d6e9cfa9e3979c7d7086e..f9038d6b109eb41b2d8a3898a2c7ff6519f2c49b 100644 (file)
@@ -200,8 +200,10 @@ static void tcp_reinit_congestion_control(struct sock *sk,
        icsk->icsk_ca_ops = ca;
        icsk->icsk_ca_setsockopt = 1;
 
-       if (sk->sk_state != TCP_CLOSE)
+       if (sk->sk_state != TCP_CLOSE) {
+               memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv));
                tcp_init_congestion_control(sk);
+       }
 }
 
 /* Manage refcounts on socket close. */
index 10d728b6804c259e459cc81a82e5c961839cc578..ab37c67756305e8548cbad657ba21a4bfc8109e0 100644 (file)
@@ -56,6 +56,7 @@ struct dctcp {
        u32 next_seq;
        u32 ce_state;
        u32 delayed_ack_reserved;
+       u32 loss_cwnd;
 };
 
 static unsigned int dctcp_shift_g __read_mostly = 4; /* g = 1/2^4 */
@@ -96,6 +97,7 @@ static void dctcp_init(struct sock *sk)
                ca->dctcp_alpha = min(dctcp_alpha_on_init, DCTCP_MAX_ALPHA);
 
                ca->delayed_ack_reserved = 0;
+               ca->loss_cwnd = 0;
                ca->ce_state = 0;
 
                dctcp_reset(tp, ca);
@@ -111,9 +113,10 @@ static void dctcp_init(struct sock *sk)
 
 static u32 dctcp_ssthresh(struct sock *sk)
 {
-       const struct dctcp *ca = inet_csk_ca(sk);
+       struct dctcp *ca = inet_csk_ca(sk);
        struct tcp_sock *tp = tcp_sk(sk);
 
+       ca->loss_cwnd = tp->snd_cwnd;
        return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->dctcp_alpha) >> 11U), 2U);
 }
 
@@ -308,12 +311,20 @@ static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr,
        return 0;
 }
 
+static u32 dctcp_cwnd_undo(struct sock *sk)
+{
+       const struct dctcp *ca = inet_csk_ca(sk);
+
+       return max(tcp_sk(sk)->snd_cwnd, ca->loss_cwnd);
+}
+
 static struct tcp_congestion_ops dctcp __read_mostly = {
        .init           = dctcp_init,
        .in_ack_event   = dctcp_update_alpha,
        .cwnd_event     = dctcp_cwnd_event,
        .ssthresh       = dctcp_ssthresh,
        .cong_avoid     = tcp_reno_cong_avoid,
+       .undo_cwnd      = dctcp_cwnd_undo,
        .set_state      = dctcp_state,
        .get_info       = dctcp_get_info,
        .flags          = TCP_CONG_NEEDS_ECN,
index a27b9c0e27c08b4e4aeaff3d0bfdf3ae561ba4d8..c71d49ce0c9379cd68317bcc135b7a2761110887 100644 (file)
@@ -128,6 +128,23 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2;
 #define REXMIT_LOST    1 /* retransmit packets marked lost */
 #define REXMIT_NEW     2 /* FRTO-style transmit of unsent/new packets */
 
+static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb)
+{
+       static bool __once __read_mostly;
+
+       if (!__once) {
+               struct net_device *dev;
+
+               __once = true;
+
+               rcu_read_lock();
+               dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);
+               pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n",
+                       dev ? dev->name : "Unknown driver");
+               rcu_read_unlock();
+       }
+}
+
 /* Adapt the MSS value used to make delayed ack decision to the
  * real world.
  */
@@ -144,7 +161,10 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
         */
        len = skb_shinfo(skb)->gso_size ? : skb->len;
        if (len >= icsk->icsk_ack.rcv_mss) {
-               icsk->icsk_ack.rcv_mss = len;
+               icsk->icsk_ack.rcv_mss = min_t(unsigned int, len,
+                                              tcp_sk(sk)->advmss);
+               if (unlikely(icsk->icsk_ack.rcv_mss != len))
+                       tcp_gro_dev_warn(sk, skb);
        } else {
                /* Otherwise, we make more careful check taking into account,
                 * that SACKs block is variable.
index bd5e8d10893fb6abffa6b0aa65de239b0000fe5b..2259114c7242c72cadc149073c8101101c198483 100644 (file)
@@ -86,7 +86,6 @@
 
 int sysctl_tcp_tw_reuse __read_mostly;
 int sysctl_tcp_low_latency __read_mostly;
-EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
 #ifdef CONFIG_TCP_MD5SIG
 static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
@@ -1565,6 +1564,21 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(tcp_add_backlog);
 
+int tcp_filter(struct sock *sk, struct sk_buff *skb)
+{
+       struct tcphdr *th = (struct tcphdr *)skb->data;
+       unsigned int eaten = skb->len;
+       int err;
+
+       err = sk_filter_trim_cap(sk, skb, th->doff * 4);
+       if (!err) {
+               eaten -= skb->len;
+               TCP_SKB_CB(skb)->end_seq -= eaten;
+       }
+       return err;
+}
+EXPORT_SYMBOL(tcp_filter);
+
 /*
  *     From tcp_input.c
  */
@@ -1677,8 +1691,10 @@ process:
 
        nf_reset(skb);
 
-       if (sk_filter(sk, skb))
+       if (tcp_filter(sk, skb))
                goto discard_and_relse;
+       th = (const struct tcphdr *)skb->data;
+       iph = ip_hdr(skb);
 
        skb->dev = NULL;
 
@@ -1887,7 +1903,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
        struct tcp_iter_state *st = seq->private;
        struct net *net = seq_file_net(seq);
        struct inet_listen_hashbucket *ilb;
-       struct inet_connection_sock *icsk;
        struct sock *sk = cur;
 
        if (!sk) {
@@ -1909,7 +1924,6 @@ get_sk:
                        continue;
                if (sk->sk_family == st->family)
                        return sk;
-               icsk = inet_csk(sk);
        }
        spin_unlock_bh(&ilb->lock);
        st->offset = 0;
index 7d96dc2d3d08fa909f247dfbcbd0fc1eeb59862b..5bab6c3f7a2fc19937571346c93302cddaddcf18 100644 (file)
@@ -1322,7 +1322,7 @@ try_again:
                *addr_len = sizeof(*sin);
        }
        if (inet->cmsg_flags)
-               ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr) + off);
+               ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr), off);
 
        err = copied;
        if (flags & MSG_TRUNC)
@@ -1345,7 +1345,7 @@ csum_copy_err:
        goto try_again;
 }
 
-int udp_disconnect(struct sock *sk, int flags)
+int __udp_disconnect(struct sock *sk, int flags)
 {
        struct inet_sock *inet = inet_sk(sk);
        /*
@@ -1367,6 +1367,15 @@ int udp_disconnect(struct sock *sk, int flags)
        sk_dst_reset(sk);
        return 0;
 }
+EXPORT_SYMBOL(__udp_disconnect);
+
+int udp_disconnect(struct sock *sk, int flags)
+{
+       lock_sock(sk);
+       __udp_disconnect(sk, flags);
+       release_sock(sk);
+       return 0;
+}
 EXPORT_SYMBOL(udp_disconnect);
 
 void udp_lib_unhash(struct sock *sk)
@@ -1446,7 +1455,7 @@ static void udp_v4_rehash(struct sock *sk)
        udp_lib_rehash(sk, new_hash);
 }
 
-static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int rc;
 
@@ -1643,10 +1652,10 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 
        if (use_hash2) {
                hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
-                           udp_table.mask;
-               hash2 = udp4_portaddr_hash(net, daddr, hnum) & udp_table.mask;
+                           udptable->mask;
+               hash2 = udp4_portaddr_hash(net, daddr, hnum) & udptable->mask;
 start_lookup:
-               hslot = &udp_table.hash2[hash2];
+               hslot = &udptable->hash2[hash2];
                offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node);
        }
 
@@ -2193,7 +2202,7 @@ int udp_abort(struct sock *sk, int err)
 
        sk->sk_err = err;
        sk->sk_error_report(sk);
-       udp_disconnect(sk, 0);
+       __udp_disconnect(sk, 0);
 
        release_sock(sk);
 
index 7e0fe4bdd96702256b7608ad3fe45df114573702..feb50a16398dfa856fd928fe823b4f6556d2caa1 100644 (file)
@@ -25,7 +25,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
                int flags, int *addr_len);
 int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
                 int flags);
-int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
 void udp_destroy_sock(struct sock *sk);
 
 #ifdef CONFIG_PROC_FS
index f9333c9636076501fbc8df1806ee057dabddb4a5..b2be1d9757efb8ce8b82dc0a0fe3a475d193ea5b 100644 (file)
@@ -295,7 +295,7 @@ unflush:
 
        skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
        skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
-       pp = udp_sk(sk)->gro_receive(sk, head, skb);
+       pp = call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
 
 out_unlock:
        rcu_read_unlock();
index af817158d830c0da080935ba29e012dffbb89112..ff450c2aad9be8a5e751772b1da5840ce1254839 100644 (file)
@@ -50,7 +50,7 @@ struct proto  udplite_prot = {
        .sendmsg           = udp_sendmsg,
        .recvmsg           = udp_recvmsg,
        .sendpage          = udp_sendpage,
-       .backlog_rcv       = udp_queue_rcv_skb,
+       .backlog_rcv       = __udp_queue_rcv_skb,
        .hash              = udp_lib_hash,
        .unhash            = udp_lib_unhash,
        .get_port          = udp_v4_get_port,
index d8983e15f85945343ab85b85b0e1c5cb9916b6ab..4bc5ba3ae452eb99ed3a70c0926f6bb1ed5c001a 100644 (file)
@@ -147,9 +147,8 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
 }
 #endif
 
-static void __ipv6_regen_rndid(struct inet6_dev *idev);
-static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
-static void ipv6_regen_rndid(unsigned long data);
+static void ipv6_regen_rndid(struct inet6_dev *idev);
+static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
 
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
 static int ipv6_count_addresses(struct inet6_dev *idev);
@@ -184,7 +183,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
 
 static void addrconf_dad_start(struct inet6_ifaddr *ifp);
 static void addrconf_dad_work(struct work_struct *w);
-static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id);
 static void addrconf_dad_run(struct inet6_dev *idev);
 static void addrconf_rs_timer(unsigned long data);
 static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
@@ -409,9 +408,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
                goto err_release;
        }
 
-       /* One reference from device.  We must do this before
-        * we invoke __ipv6_regen_rndid().
-        */
+       /* One reference from device. */
        in6_dev_hold(ndev);
 
        if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
@@ -425,17 +422,15 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
 #endif
 
        INIT_LIST_HEAD(&ndev->tempaddr_list);
-       setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);
+       ndev->desync_factor = U32_MAX;
        if ((dev->flags&IFF_LOOPBACK) ||
            dev->type == ARPHRD_TUNNEL ||
            dev->type == ARPHRD_TUNNEL6 ||
            dev->type == ARPHRD_SIT ||
            dev->type == ARPHRD_NONE) {
                ndev->cnf.use_tempaddr = -1;
-       } else {
-               in6_dev_hold(ndev);
-               ipv6_regen_rndid((unsigned long) ndev);
-       }
+       } else
+               ipv6_regen_rndid(ndev);
 
        ndev->token = in6addr_any;
 
@@ -447,7 +442,6 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
        err = addrconf_sysctl_register(ndev);
        if (err) {
                ipv6_mc_destroy_dev(ndev);
-               del_timer(&ndev->regen_timer);
                snmp6_unregister_dev(ndev);
                goto err_release;
        }
@@ -1190,6 +1184,8 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
        int ret = 0;
        u32 addr_flags;
        unsigned long now = jiffies;
+       long max_desync_factor;
+       s32 cnf_temp_preferred_lft;
 
        write_lock_bh(&idev->lock);
        if (ift) {
@@ -1222,23 +1218,42 @@ retry:
        }
        in6_ifa_hold(ifp);
        memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
-       __ipv6_try_regen_rndid(idev, tmpaddr);
+       ipv6_try_regen_rndid(idev, tmpaddr);
        memcpy(&addr.s6_addr[8], idev->rndid, 8);
        age = (now - ifp->tstamp) / HZ;
+
+       regen_advance = idev->cnf.regen_max_retry *
+                       idev->cnf.dad_transmits *
+                       NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
+
+       /* recalculate max_desync_factor each time and update
+        * idev->desync_factor if it's larger
+        */
+       cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft);
+       max_desync_factor = min_t(__u32,
+                                 idev->cnf.max_desync_factor,
+                                 cnf_temp_preferred_lft - regen_advance);
+
+       if (unlikely(idev->desync_factor > max_desync_factor)) {
+               if (max_desync_factor > 0) {
+                       get_random_bytes(&idev->desync_factor,
+                                        sizeof(idev->desync_factor));
+                       idev->desync_factor %= max_desync_factor;
+               } else {
+                       idev->desync_factor = 0;
+               }
+       }
+
        tmp_valid_lft = min_t(__u32,
                              ifp->valid_lft,
                              idev->cnf.temp_valid_lft + age);
-       tmp_prefered_lft = min_t(__u32,
-                                ifp->prefered_lft,
-                                idev->cnf.temp_prefered_lft + age -
-                                idev->cnf.max_desync_factor);
+       tmp_prefered_lft = cnf_temp_preferred_lft + age -
+                           idev->desync_factor;
+       tmp_prefered_lft = min_t(__u32, ifp->prefered_lft, tmp_prefered_lft);
        tmp_plen = ifp->prefix_len;
        tmp_tstamp = ifp->tstamp;
        spin_unlock_bh(&ifp->lock);
 
-       regen_advance = idev->cnf.regen_max_retry *
-                       idev->cnf.dad_transmits *
-                       NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
        write_unlock_bh(&idev->lock);
 
        /* A temporary address is created only if this calculated Preferred
@@ -2150,7 +2165,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
 }
 
 /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
-static void __ipv6_regen_rndid(struct inet6_dev *idev)
+static void ipv6_regen_rndid(struct inet6_dev *idev)
 {
 regen:
        get_random_bytes(idev->rndid, sizeof(idev->rndid));
@@ -2179,43 +2194,10 @@ regen:
        }
 }
 
-static void ipv6_regen_rndid(unsigned long data)
-{
-       struct inet6_dev *idev = (struct inet6_dev *) data;
-       unsigned long expires;
-
-       rcu_read_lock_bh();
-       write_lock_bh(&idev->lock);
-
-       if (idev->dead)
-               goto out;
-
-       __ipv6_regen_rndid(idev);
-
-       expires = jiffies +
-               idev->cnf.temp_prefered_lft * HZ -
-               idev->cnf.regen_max_retry * idev->cnf.dad_transmits *
-               NEIGH_VAR(idev->nd_parms, RETRANS_TIME) -
-               idev->cnf.max_desync_factor * HZ;
-       if (time_before(expires, jiffies)) {
-               pr_warn("%s: too short regeneration interval; timer disabled for %s\n",
-                       __func__, idev->dev->name);
-               goto out;
-       }
-
-       if (!mod_timer(&idev->regen_timer, expires))
-               in6_dev_hold(idev);
-
-out:
-       write_unlock_bh(&idev->lock);
-       rcu_read_unlock_bh();
-       in6_dev_put(idev);
-}
-
-static void  __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr)
+static void  ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr)
 {
        if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0)
-               __ipv6_regen_rndid(idev);
+               ipv6_regen_rndid(idev);
 }
 
 /*
@@ -2356,7 +2338,7 @@ static void manage_tempaddrs(struct inet6_dev *idev,
                        max_valid = 0;
 
                max_prefered = idev->cnf.temp_prefered_lft -
-                              idev->cnf.max_desync_factor - age;
+                              idev->desync_factor - age;
                if (max_prefered < 0)
                        max_prefered = 0;
 
@@ -2916,6 +2898,7 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
                spin_lock_bh(&ifp->lock);
                ifp->flags &= ~IFA_F_TENTATIVE;
                spin_unlock_bh(&ifp->lock);
+               rt_genid_bump_ipv6(dev_net(idev->dev));
                ipv6_ifa_notify(RTM_NEWADDR, ifp);
                in6_ifa_put(ifp);
        }
@@ -3018,7 +3001,7 @@ static void init_loopback(struct net_device *dev)
                                 * lo device down, release this obsolete dst and
                                 * reallocate a new router for ifa.
                                 */
-                               if (sp_ifa->rt->dst.obsolete > 0) {
+                               if (!atomic_read(&sp_ifa->rt->rt6i_ref)) {
                                        ip6_rt_put(sp_ifa->rt);
                                        sp_ifa->rt = NULL;
                                } else {
@@ -3594,9 +3577,6 @@ restart:
        if (!how)
                idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
 
-       if (how && del_timer(&idev->regen_timer))
-               in6_dev_put(idev);
-
        /* Step 3: clear tempaddr list */
        while (!list_empty(&idev->tempaddr_list)) {
                ifa = list_first_entry(&idev->tempaddr_list,
@@ -3761,7 +3741,7 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
 {
        struct inet6_dev *idev = ifp->idev;
        struct net_device *dev = idev->dev;
-       bool notify = false;
+       bool bump_id, notify = false;
 
        addrconf_join_solict(dev, &ifp->addr);
 
@@ -3776,11 +3756,12 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
            idev->cnf.accept_dad < 1 ||
            !(ifp->flags&IFA_F_TENTATIVE) ||
            ifp->flags & IFA_F_NODAD) {
+               bump_id = ifp->flags & IFA_F_TENTATIVE;
                ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
                spin_unlock(&ifp->lock);
                read_unlock_bh(&idev->lock);
 
-               addrconf_dad_completed(ifp);
+               addrconf_dad_completed(ifp, bump_id);
                return;
        }
 
@@ -3840,8 +3821,8 @@ static void addrconf_dad_work(struct work_struct *w)
                                                struct inet6_ifaddr,
                                                dad_work);
        struct inet6_dev *idev = ifp->idev;
+       bool bump_id, disable_ipv6 = false;
        struct in6_addr mcaddr;
-       bool disable_ipv6 = false;
 
        enum {
                DAD_PROCESS,
@@ -3911,11 +3892,12 @@ static void addrconf_dad_work(struct work_struct *w)
                 * DAD was successful
                 */
 
+               bump_id = ifp->flags & IFA_F_TENTATIVE;
                ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
                spin_unlock(&ifp->lock);
                write_unlock_bh(&idev->lock);
 
-               addrconf_dad_completed(ifp);
+               addrconf_dad_completed(ifp, bump_id);
 
                goto out;
        }
@@ -3952,7 +3934,7 @@ static bool ipv6_lonely_lladdr(struct inet6_ifaddr *ifp)
        return true;
 }
 
-static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id)
 {
        struct net_device *dev = ifp->idev->dev;
        struct in6_addr lladdr;
@@ -4004,6 +3986,9 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
                spin_unlock(&ifp->lock);
                write_unlock_bh(&ifp->idev->lock);
        }
+
+       if (bump_id)
+               rt_genid_bump_ipv6(dev_net(dev));
 }
 
 static void addrconf_dad_run(struct inet6_dev *idev)
index 37874e2f30edf98f31e2a5097761143d507d5b95..ccf40550c475d31bcbc0565daa4a81428e5c9c58 100644 (file)
@@ -139,7 +139,8 @@ void ip6_datagram_release_cb(struct sock *sk)
 }
 EXPORT_SYMBOL_GPL(ip6_datagram_release_cb);
 
-static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr,
+                          int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
        struct inet_sock        *inet = inet_sk(sk);
@@ -252,6 +253,7 @@ ipv4_connected:
 out:
        return err;
 }
+EXPORT_SYMBOL_GPL(__ip6_datagram_connect);
 
 int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
index 060a60b2f8a6db074167e389b56893337c887fe9..111ba55fd512fb9f2b6f6af6c7084b71cc9bbf22 100644 (file)
@@ -418,7 +418,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
                esph = (void *)skb_push(skb, 4);
                *seqhi = esph->spi;
                esph->spi = esph->seq_no;
-               esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.input.hi);
+               esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi;
                aead_request_set_callback(req, 0, esp_input_done_esn, skb);
        }
 
index bd59c343d35f297ff6c0462cac4cc76c6c9b76ed..2772004ba5a18848bd818434951fb10d758be90d 100644 (file)
@@ -447,8 +447,10 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
 
        if (__ipv6_addr_needs_scope_id(addr_type))
                iif = skb->dev->ifindex;
-       else
-               iif = l3mdev_master_ifindex(skb->dev);
+       else {
+               dst = skb_dst(skb);
+               iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev);
+       }
 
        /*
         *      Must not send error if the source does not uniquely
index 00cf28ad45650c801c90c37fb571acb7d1615183..02761c9fe43eb306fa1887e577130e5abd2aa2b8 100644 (file)
@@ -96,7 +96,7 @@ EXPORT_SYMBOL(__inet6_lookup_established);
 static inline int compute_score(struct sock *sk, struct net *net,
                                const unsigned short hnum,
                                const struct in6_addr *daddr,
-                               const int dif)
+                               const int dif, bool exact_dif)
 {
        int score = -1;
 
@@ -109,7 +109,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
                                return -1;
                        score++;
                }
-               if (sk->sk_bound_dev_if) {
+               if (sk->sk_bound_dev_if || exact_dif) {
                        if (sk->sk_bound_dev_if != dif)
                                return -1;
                        score++;
@@ -131,11 +131,12 @@ struct sock *inet6_lookup_listener(struct net *net,
        unsigned int hash = inet_lhashfn(net, hnum);
        struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
        int score, hiscore = 0, matches = 0, reuseport = 0;
+       bool exact_dif = inet6_exact_dif_match(net, skb);
        struct sock *sk, *result = NULL;
        u32 phash = 0;
 
        sk_for_each(sk, &ilb->head) {
-               score = compute_score(sk, net, hnum, daddr, dif);
+               score = compute_score(sk, net, hnum, daddr, dif, exact_dif);
                if (score > hiscore) {
                        reuseport = sk->sk_reuseport;
                        if (reuseport) {
@@ -263,13 +264,15 @@ EXPORT_SYMBOL_GPL(inet6_hash_connect);
 
 int inet6_hash(struct sock *sk)
 {
+       int err = 0;
+
        if (sk->sk_state != TCP_CLOSE) {
                local_bh_disable();
-               __inet_hash(sk, NULL, ipv6_rcv_saddr_equal);
+               err = __inet_hash(sk, NULL, ipv6_rcv_saddr_equal);
                local_bh_enable();
        }
 
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(inet6_hash);
 
index e7bfd55899a34ab8a314ecdfb9a98d8a55d0af15..89c59e656f44939863ceada610d3442d2de666ba 100644 (file)
@@ -99,7 +99,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
                segs = ops->callbacks.gso_segment(skb, features);
        }
 
-       if (IS_ERR(segs))
+       if (IS_ERR_OR_NULL(segs))
                goto out;
 
        gso_partial = !!(skb_shinfo(segs)->gso_type & SKB_GSO_PARTIAL);
@@ -246,7 +246,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
 
        skb_gro_postpull_rcsum(skb, iph, nlen);
 
-       pp = ops->callbacks.gro_receive(head, skb);
+       pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
 
 out_unlock:
        rcu_read_unlock();
index 6001e781164eb6d49cf604e7d8067a42ebc7dc3d..59eb4ed99ce80c0b6fd2ece1a877e3c9a1d57bcc 100644 (file)
@@ -1366,7 +1366,7 @@ emsgsize:
        if (((length > mtu) ||
             (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
-           (rt->dst.dev->features & NETIF_F_UFO) &&
+           (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
            (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) {
                err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
                                          hh_len, fragheaderlen, exthdrlen,
index 6a66adba0c229a0fd11c5806163a4cb87eb9483c..d76674efe523cf041bf2ef57f5b861b3707dd05e 100644 (file)
@@ -157,6 +157,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_
        hash = HASH(&any, local);
        for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
+                   ipv6_addr_any(&t->parms.raddr) &&
                    (t->dev->flags & IFF_UP))
                        return t;
        }
@@ -164,6 +165,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_
        hash = HASH(remote, &any);
        for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
                if (ipv6_addr_equal(remote, &t->parms.raddr) &&
+                   ipv6_addr_any(&t->parms.laddr) &&
                    (t->dev->flags & IFF_UP))
                        return t;
        }
@@ -1032,6 +1034,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
        int mtu;
        unsigned int psh_hlen = sizeof(struct ipv6hdr) + t->encap_hlen;
        unsigned int max_headroom = psh_hlen;
+       bool use_cache = false;
        u8 hop_limit;
        int err = -1;
 
@@ -1064,7 +1067,15 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
 
                memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
                neigh_release(neigh);
-       } else if (!fl6->flowi6_mark)
+       } else if (!(t->parms.flags &
+                    (IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) {
+               /* enable the cache only only if the routing decision does
+                * not depend on the current inner header value
+                */
+               use_cache = true;
+       }
+
+       if (use_cache)
                dst = dst_cache_get(&t->dst_cache);
 
        if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
@@ -1148,7 +1159,7 @@ route_lookup:
                if (t->encap.type != TUNNEL_ENCAP_NONE)
                        goto tx_err_dst_release;
        } else {
-               if (!fl6->flowi6_mark && ndst)
+               if (use_cache && ndst)
                        dst_cache_set_ip6(&t->dst_cache, ndst, &fl6->saddr);
        }
        skb_dst_set(skb, dst);
index a7520528ecd27fae3d8ccee03c76345f0776234a..b283f293ee4ae7537da0bde51b5a4695a2e6f249 100644 (file)
@@ -88,9 +88,6 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
 
        uh->len = htons(skb->len);
 
-       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
-       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
-                           | IPSKB_REROUTED);
        skb_dst_set(skb, dst);
 
        udp6_set_csum(nocheck, skb, saddr, daddr, skb->len);
index 8a02ca8a11af4b388bfe996711458efd46b641cf..c299c1e2bbf06ed31bc9fd30c7c96111fe606fc5 100644 (file)
@@ -1138,6 +1138,33 @@ static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = {
        .priority       =       100,
 };
 
+static bool is_vti6_tunnel(const struct net_device *dev)
+{
+       return dev->netdev_ops == &vti6_netdev_ops;
+}
+
+static int vti6_device_event(struct notifier_block *unused,
+                            unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct ip6_tnl *t = netdev_priv(dev);
+
+       if (!is_vti6_tunnel(dev))
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_DOWN:
+               if (!net_eq(t->net, dev_net(dev)))
+                       xfrm_garbage_collect(t->net);
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block vti6_notifier_block __read_mostly = {
+       .notifier_call = vti6_device_event,
+};
+
 /**
  * vti6_tunnel_init - register protocol and reserve needed resources
  *
@@ -1148,6 +1175,8 @@ static int __init vti6_tunnel_init(void)
        const char *msg;
        int err;
 
+       register_netdevice_notifier(&vti6_notifier_block);
+
        msg = "tunnel device";
        err = register_pernet_device(&vti6_net_ops);
        if (err < 0)
@@ -1180,6 +1209,7 @@ xfrm_proto_ah_failed:
 xfrm_proto_esp_failed:
        unregister_pernet_device(&vti6_net_ops);
 pernet_dev_failed:
+       unregister_netdevice_notifier(&vti6_notifier_block);
        pr_err("vti6 init: failed to register %s\n", msg);
        return err;
 }
@@ -1194,6 +1224,7 @@ static void __exit vti6_tunnel_cleanup(void)
        xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
        xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
        unregister_pernet_device(&vti6_net_ops);
+       unregister_netdevice_notifier(&vti6_notifier_block);
 }
 
 module_init(vti6_tunnel_init);
index 5330262ab673c022fbf700d22782a74ccd1494fe..636ec56f5f5028277fc69721464ba734621a91e0 100644 (file)
@@ -120,6 +120,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
 static bool setsockopt_needs_rtnl(int optname)
 {
        switch (optname) {
+       case IPV6_ADDRFORM:
        case IPV6_ADD_MEMBERSHIP:
        case IPV6_DROP_MEMBERSHIP:
        case IPV6_JOIN_ANYCAST:
@@ -198,7 +199,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                        }
 
                        fl6_free_socklist(sk);
-                       ipv6_sock_mc_close(sk);
+                       __ipv6_sock_mc_close(sk);
 
                        /*
                         * Sock is moving from IPv6 to IPv4 (sk_prot), so
index 75c1fc54f188939c4ed78a7323e8907c5e3b9be9..14a3903f1c82d83d44c39befdfe827833d09b13c 100644 (file)
@@ -276,16 +276,14 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
        return idev;
 }
 
-void ipv6_sock_mc_close(struct sock *sk)
+void __ipv6_sock_mc_close(struct sock *sk)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct ipv6_mc_socklist *mc_lst;
        struct net *net = sock_net(sk);
 
-       if (!rcu_access_pointer(np->ipv6_mc_list))
-               return;
+       ASSERT_RTNL();
 
-       rtnl_lock();
        while ((mc_lst = rtnl_dereference(np->ipv6_mc_list)) != NULL) {
                struct net_device *dev;
 
@@ -303,8 +301,17 @@ void ipv6_sock_mc_close(struct sock *sk)
 
                atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
                kfree_rcu(mc_lst, rcu);
-
        }
+}
+
+void ipv6_sock_mc_close(struct sock *sk)
+{
+       struct ipv6_pinfo *np = inet6_sk(sk);
+
+       if (!rcu_access_pointer(np->ipv6_mc_list))
+               return;
+       rtnl_lock();
+       __ipv6_sock_mc_close(sk);
        rtnl_unlock();
 }
 
index e4347aeb2e65337a1adbf82f66befc22a83c6606..9948b5ce52dad3a823edede517f17069bd7226dc 100644 (file)
@@ -576,11 +576,11 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
        /* Jumbo payload inhibits frag. header */
        if (ipv6_hdr(skb)->payload_len == 0) {
                pr_debug("payload len = 0\n");
-               return -EINVAL;
+               return 0;
        }
 
        if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0)
-               return -EINVAL;
+               return 0;
 
        if (!pskb_may_pull(skb, fhoff + sizeof(*fhdr)))
                return -ENOMEM;
index f7aab5ab93a558bd7d60010e15ca15169d1d0ba7..f06b0471f39fc0130f9db69e6c05330e8d5c6909 100644 (file)
@@ -69,7 +69,7 @@ static unsigned int ipv6_defrag(void *priv,
        if (err == -EINPROGRESS)
                return NF_STOLEN;
 
-       return NF_ACCEPT;
+       return err == 0 ? NF_ACCEPT : NF_DROP;
 }
 
 static struct nf_hook_ops ipv6_defrag_ops[] = {
index a5400223fd743ff012ab7318c7ad6845c1f6b36c..10090400c72f19b7dd21d6543a2c1d740a9bd595 100644 (file)
@@ -156,6 +156,7 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
        fl6.daddr = oip6h->saddr;
        fl6.fl6_sport = otcph->dest;
        fl6.fl6_dport = otcph->source;
+       fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
        security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
        dst = ip6_route_output(net, NULL, &fl6);
        if (dst->error) {
index 8bfd470cbe726678c5da89dff4f24b9fa089b356..831f86e1ec08270b4aeed8924ebe09b978953e44 100644 (file)
@@ -26,7 +26,7 @@ static void nft_dup_ipv6_eval(const struct nft_expr *expr,
 {
        struct nft_dup_ipv6 *priv = nft_expr_priv(expr);
        struct in6_addr *gw = (struct in6_addr *)&regs->data[priv->sreg_addr];
-       int oif = regs->data[priv->sreg_dev];
+       int oif = priv->sreg_dev ? regs->data[priv->sreg_dev] : -1;
 
        nf_dup_ipv6(pkt->net, pkt->skb, pkt->hook, gw, oif);
 }
@@ -57,7 +57,9 @@ static int nft_dup_ipv6_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        struct nft_dup_ipv6 *priv = nft_expr_priv(expr);
 
-       if (nft_dump_register(skb, NFTA_DUP_SREG_ADDR, priv->sreg_addr) ||
+       if (nft_dump_register(skb, NFTA_DUP_SREG_ADDR, priv->sreg_addr))
+               goto nla_put_failure;
+       if (priv->sreg_dev &&
            nft_dump_register(skb, NFTA_DUP_SREG_DEV, priv->sreg_dev))
                goto nla_put_failure;
 
index 7cca8ac66fe9b07a9f91559667c057113ccc3c19..cd4252346a32d90e8e133bd985811b6241e4bcd7 100644 (file)
@@ -155,6 +155,8 @@ int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
        if (unlikely(!skb))
                return 0;
 
+       skb->protocol = htons(ETH_P_IPV6);
+
        return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
                       net, sk, skb, NULL, skb_dst(skb)->dev,
                       dst_output);
index 0e983b694ee805dc662a49ae5f6c9438b5ed931d..66e2d9dfc43a87ebed092d024e5bf2752b755d0e 100644 (file)
@@ -180,7 +180,7 @@ struct proto pingv6_prot = {
        .init =         ping_init_sock,
        .close =        ping_close,
        .connect =      ip6_datagram_connect_v6_only,
-       .disconnect =   udp_disconnect,
+       .disconnect =   __udp_disconnect,
        .setsockopt =   ipv6_setsockopt,
        .getsockopt =   ipv6_getsockopt,
        .sendmsg =      ping_v6_sendmsg,
index 54404f08efccaa62ddee0d4233f43be0f353c7ce..054a1d84fc5e940577d9c96fad3578d7038833b9 100644 (file)
@@ -1241,7 +1241,7 @@ struct proto rawv6_prot = {
        .close             = rawv6_close,
        .destroy           = raw6_destroy,
        .connect           = ip6_datagram_connect_v6_only,
-       .disconnect        = udp_disconnect,
+       .disconnect        = __udp_disconnect,
        .ioctl             = rawv6_ioctl,
        .init              = rawv6_init_sk,
        .setsockopt        = rawv6_setsockopt,
index 2160d5d009cb6e97f36f3b4319322fb52a354866..3815e8505ed2a3be767dae4ec9822d2152c4e72e 100644 (file)
@@ -456,7 +456,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
        skb_network_header(head)[nhoff] = skb_transport_header(head)[0];
        memmove(head->head + sizeof(struct frag_hdr), head->head,
                (head->data - head->head) - sizeof(struct frag_hdr));
-       head->mac_header += sizeof(struct frag_hdr);
+       if (skb_mac_header_was_set(head))
+               head->mac_header += sizeof(struct frag_hdr);
        head->network_header += sizeof(struct frag_hdr);
 
        skb_reset_transport_header(head);
index bdbc38e8bf2906d48439928f08adf4b880469b60..1b57e11e6e0db40e233600e465e44afa0b1e714f 100644 (file)
@@ -102,11 +102,13 @@ static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
 #ifdef CONFIG_IPV6_ROUTE_INFO
 static struct rt6_info *rt6_add_route_info(struct net *net,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex,
+                                          const struct in6_addr *gwaddr,
+                                          struct net_device *dev,
                                           unsigned int pref);
 static struct rt6_info *rt6_get_route_info(struct net *net,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex);
+                                          const struct in6_addr *gwaddr,
+                                          struct net_device *dev);
 #endif
 
 struct uncached_list {
@@ -656,7 +658,8 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
        struct net_device *dev = rt->dst.dev;
 
        if (dev && !netif_carrier_ok(dev) &&
-           idev->cnf.ignore_routes_with_linkdown)
+           idev->cnf.ignore_routes_with_linkdown &&
+           !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
                goto out;
 
        if (rt6_check_expired(rt))
@@ -803,7 +806,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
                rt = rt6_get_dflt_router(gwaddr, dev);
        else
                rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
-                                       gwaddr, dev->ifindex);
+                                       gwaddr, dev);
 
        if (rt && !lifetime) {
                ip6_del_rt(rt);
@@ -811,8 +814,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
        }
 
        if (!rt && lifetime)
-               rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
-                                       pref);
+               rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
+                                       dev, pref);
        else if (rt)
                rt->rt6i_flags = RTF_ROUTEINFO |
                                 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
@@ -1050,6 +1053,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
        int strict = 0;
 
        strict |= flags & RT6_LOOKUP_F_IFACE;
+       strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
        if (net->ipv6.devconf_all->forwarding == 0)
                strict |= RT6_LOOKUP_F_REACHABLE;
 
@@ -1360,6 +1364,9 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
        if (rt6->rt6i_flags & RTF_LOCAL)
                return;
 
+       if (dst_metric_locked(dst, RTAX_MTU))
+               return;
+
        dst_confirm(dst);
        mtu = max_t(u32, mtu, IPV6_MIN_MTU);
        if (mtu >= dst_mtu(dst))
@@ -1789,7 +1796,7 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net,
        };
        struct fib6_table *table;
        struct rt6_info *rt;
-       int flags = RT6_LOOKUP_F_IFACE;
+       int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
 
        table = fib6_get_table(net, cfg->fc_table);
        if (!table)
@@ -2325,13 +2332,16 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
 #ifdef CONFIG_IPV6_ROUTE_INFO
 static struct rt6_info *rt6_get_route_info(struct net *net,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex)
+                                          const struct in6_addr *gwaddr,
+                                          struct net_device *dev)
 {
+       u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
+       int ifindex = dev->ifindex;
        struct fib6_node *fn;
        struct rt6_info *rt = NULL;
        struct fib6_table *table;
 
-       table = fib6_get_table(net, RT6_TABLE_INFO);
+       table = fib6_get_table(net, tb_id);
        if (!table)
                return NULL;
 
@@ -2357,12 +2367,13 @@ out:
 
 static struct rt6_info *rt6_add_route_info(struct net *net,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex,
+                                          const struct in6_addr *gwaddr,
+                                          struct net_device *dev,
                                           unsigned int pref)
 {
        struct fib6_config cfg = {
                .fc_metric      = IP6_RT_PRIO_USER,
-               .fc_ifindex     = ifindex,
+               .fc_ifindex     = dev->ifindex,
                .fc_dst_len     = prefixlen,
                .fc_flags       = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
                                  RTF_UP | RTF_PREF(pref),
@@ -2371,7 +2382,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
                .fc_nlinfo.nl_net = net,
        };
 
-       cfg.fc_table = l3mdev_fib_table_by_index(net, ifindex) ? : RT6_TABLE_INFO;
+       cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
        cfg.fc_dst = *prefix;
        cfg.fc_gateway = *gwaddr;
 
@@ -2381,16 +2392,17 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
 
        ip6_route_add(&cfg);
 
-       return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
+       return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
 }
 #endif
 
 struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
 {
+       u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
        struct rt6_info *rt;
        struct fib6_table *table;
 
-       table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
+       table = fib6_get_table(dev_net(dev), tb_id);
        if (!table)
                return NULL;
 
@@ -2424,20 +2436,20 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
 
        cfg.fc_gateway = *gwaddr;
 
-       ip6_route_add(&cfg);
+       if (!ip6_route_add(&cfg)) {
+               struct fib6_table *table;
+
+               table = fib6_get_table(dev_net(dev), cfg.fc_table);
+               if (table)
+                       table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
+       }
 
        return rt6_get_dflt_router(gwaddr, dev);
 }
 
-void rt6_purge_dflt_routers(struct net *net)
+static void __rt6_purge_dflt_routers(struct fib6_table *table)
 {
        struct rt6_info *rt;
-       struct fib6_table *table;
-
-       /* NOTE: Keep consistent with rt6_get_dflt_router */
-       table = fib6_get_table(net, RT6_TABLE_DFLT);
-       if (!table)
-               return;
 
 restart:
        read_lock_bh(&table->tb6_lock);
@@ -2451,6 +2463,27 @@ restart:
                }
        }
        read_unlock_bh(&table->tb6_lock);
+
+       table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
+}
+
+void rt6_purge_dflt_routers(struct net *net)
+{
+       struct fib6_table *table;
+       struct hlist_head *head;
+       unsigned int h;
+
+       rcu_read_lock();
+
+       for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
+               head = &net->ipv6.fib_table_hash[h];
+               hlist_for_each_entry_rcu(table, head, tb6_hlist) {
+                       if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
+                               __rt6_purge_dflt_routers(table);
+               }
+       }
+
+       rcu_read_unlock();
 }
 
 static void rtmsg_to_fib6_config(struct net *net,
@@ -2728,6 +2761,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
           PMTU discouvery.
         */
        if (rt->dst.dev == arg->dev &&
+           dst_metric_raw(&rt->dst, RTAX_MTU) &&
            !dst_metric_locked(&rt->dst, RTAX_MTU)) {
                if (rt->rt6i_flags & RTF_CACHE) {
                        /* For RTF_CACHE with rt6i_pmtu == 0
index 5a27ab4eab3974280aad827241944b53daab569e..b9f1fee9a8862a5bc17a20e17bdb402adc418cde 100644 (file)
@@ -818,8 +818,12 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
        fl6.flowi6_proto = IPPROTO_TCP;
        if (rt6_need_strict(&fl6.daddr) && !oif)
                fl6.flowi6_oif = tcp_v6_iif(skb);
-       else
-               fl6.flowi6_oif = oif ? : skb->skb_iif;
+       else {
+               if (!oif && netif_index_is_l3_master(net, skb->skb_iif))
+                       oif = skb->skb_iif;
+
+               fl6.flowi6_oif = oif;
+       }
 
        fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
        fl6.fl6_dport = t1->dest;
@@ -1225,7 +1229,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
        if (skb->protocol == htons(ETH_P_IP))
                return tcp_v4_do_rcv(sk, skb);
 
-       if (sk_filter(sk, skb))
+       if (tcp_filter(sk, skb))
                goto discard;
 
        /*
@@ -1453,8 +1457,10 @@ process:
        if (tcp_v6_inbound_md5_hash(sk, skb))
                goto discard_and_relse;
 
-       if (sk_filter(sk, skb))
+       if (tcp_filter(sk, skb))
                goto discard_and_relse;
+       th = (const struct tcphdr *)skb->data;
+       hdr = ipv6_hdr(skb);
 
        skb->dev = NULL;
 
index 9aa7c1c7a9ce1d98f51ff547b936eacc5f671cd4..e4a8000d59ad6f9d3da1043f4c21c63e9deb6e5b 100644 (file)
@@ -427,7 +427,8 @@ try_again:
 
        if (is_udp4) {
                if (inet->cmsg_flags)
-                       ip_cmsg_recv(msg, skb);
+                       ip_cmsg_recv_offset(msg, skb,
+                                           sizeof(struct udphdr), off);
        } else {
                if (np->rxopt.all)
                        ip6_datagram_recv_specific_ctl(sk, msg, skb);
@@ -513,7 +514,7 @@ out:
        return;
 }
 
-static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int rc;
 
@@ -705,10 +706,10 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 
        if (use_hash2) {
                hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) &
-                           udp_table.mask;
-               hash2 = udp6_portaddr_hash(net, daddr, hnum) & udp_table.mask;
+                           udptable->mask;
+               hash2 = udp6_portaddr_hash(net, daddr, hnum) & udptable->mask;
 start_lookup:
-               hslot = &udp_table.hash2[hash2];
+               hslot = &udptable->hash2[hash2];
                offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node);
        }
 
index f6eb1ab34f4bc50e321e74f129feee4118f03807..e78bdc76dcc33ceda888fb323a530f774057edbb 100644 (file)
@@ -26,7 +26,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
 int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
 int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
                  int flags, int *addr_len);
-int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
 void udpv6_destroy_sock(struct sock *sk);
 
 #ifdef CONFIG_PROC_FS
index 47d0d2b87106558fece3496479198005c55b99e7..2f5101a1228335030f1965056bd22ad4318768b4 100644 (file)
@@ -45,7 +45,7 @@ struct proto udplitev6_prot = {
        .getsockopt        = udpv6_getsockopt,
        .sendmsg           = udpv6_sendmsg,
        .recvmsg           = udpv6_recvmsg,
-       .backlog_rcv       = udpv6_queue_rcv_skb,
+       .backlog_rcv       = __udpv6_queue_rcv_skb,
        .hash              = udp_lib_hash,
        .unhash            = udp_lib_unhash,
        .get_port          = udp_v6_get_port,
index 42de4ccd159f6f6853930afd44cea239e2011a54..8938b6ba57a037b6f95f9dcfd2461d7c3951cdfb 100644 (file)
@@ -61,7 +61,8 @@ static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif
                if ((l2tp->conn_id == tunnel_id) &&
                    net_eq(sock_net(sk), net) &&
                    !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
-                   !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
+                   (!sk->sk_bound_dev_if || !dif ||
+                    sk->sk_bound_dev_if == dif))
                        goto found;
        }
 
@@ -182,15 +183,17 @@ pass_up:
                struct iphdr *iph = (struct iphdr *) skb_network_header(skb);
 
                read_lock_bh(&l2tp_ip_lock);
-               sk = __l2tp_ip_bind_lookup(net, iph->daddr, 0, tunnel_id);
+               sk = __l2tp_ip_bind_lookup(net, iph->daddr, inet_iif(skb),
+                                          tunnel_id);
+               if (!sk) {
+                       read_unlock_bh(&l2tp_ip_lock);
+                       goto discard;
+               }
+
+               sock_hold(sk);
                read_unlock_bh(&l2tp_ip_lock);
        }
 
-       if (sk == NULL)
-               goto discard;
-
-       sock_hold(sk);
-
        if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_put;
 
@@ -251,22 +254,17 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        int ret;
        int chk_addr_ret;
 
-       if (!sock_flag(sk, SOCK_ZAPPED))
-               return -EINVAL;
        if (addr_len < sizeof(struct sockaddr_l2tpip))
                return -EINVAL;
        if (addr->l2tp_family != AF_INET)
                return -EINVAL;
 
-       ret = -EADDRINUSE;
-       read_lock_bh(&l2tp_ip_lock);
-       if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr,
-                                 sk->sk_bound_dev_if, addr->l2tp_conn_id))
-               goto out_in_use;
+       lock_sock(sk);
 
-       read_unlock_bh(&l2tp_ip_lock);
+       ret = -EINVAL;
+       if (!sock_flag(sk, SOCK_ZAPPED))
+               goto out;
 
-       lock_sock(sk);
        if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_l2tpip))
                goto out;
 
@@ -280,25 +278,28 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                inet->inet_rcv_saddr = inet->inet_saddr = addr->l2tp_addr.s_addr;
        if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
                inet->inet_saddr = 0;  /* Use device */
-       sk_dst_reset(sk);
 
+       write_lock_bh(&l2tp_ip_lock);
+       if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr,
+                                 sk->sk_bound_dev_if, addr->l2tp_conn_id)) {
+               write_unlock_bh(&l2tp_ip_lock);
+               ret = -EADDRINUSE;
+               goto out;
+       }
+
+       sk_dst_reset(sk);
        l2tp_ip_sk(sk)->conn_id = addr->l2tp_conn_id;
 
-       write_lock_bh(&l2tp_ip_lock);
        sk_add_bind_node(sk, &l2tp_ip_bind_table);
        sk_del_node_init(sk);
        write_unlock_bh(&l2tp_ip_lock);
+
        ret = 0;
        sock_reset_flag(sk, SOCK_ZAPPED);
 
 out:
        release_sock(sk);
 
-       return ret;
-
-out_in_use:
-       read_unlock_bh(&l2tp_ip_lock);
-
        return ret;
 }
 
@@ -307,21 +308,24 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
        struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
        int rc;
 
-       if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
-               return -EINVAL;
-
        if (addr_len < sizeof(*lsa))
                return -EINVAL;
 
        if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
                return -EINVAL;
 
-       rc = ip4_datagram_connect(sk, uaddr, addr_len);
-       if (rc < 0)
-               return rc;
-
        lock_sock(sk);
 
+       /* Must bind first - autobinding does not work */
+       if (sock_flag(sk, SOCK_ZAPPED)) {
+               rc = -EINVAL;
+               goto out_sk;
+       }
+
+       rc = __ip4_datagram_connect(sk, uaddr, addr_len);
+       if (rc < 0)
+               goto out_sk;
+
        l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
 
        write_lock_bh(&l2tp_ip_lock);
@@ -329,7 +333,9 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
        sk_add_bind_node(sk, &l2tp_ip_bind_table);
        write_unlock_bh(&l2tp_ip_lock);
 
+out_sk:
        release_sock(sk);
+
        return rc;
 }
 
@@ -338,7 +344,7 @@ static int l2tp_ip_disconnect(struct sock *sk, int flags)
        if (sock_flag(sk, SOCK_ZAPPED))
                return 0;
 
-       return udp_disconnect(sk, flags);
+       return __udp_disconnect(sk, flags);
 }
 
 static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
index ea2ae6664cc8d643319016ea7a234dc034ec590e..aa821cb639e541fa85a062deeee43516e2d4da8d 100644 (file)
@@ -72,8 +72,9 @@ static struct sock *__l2tp_ip6_bind_lookup(struct net *net,
 
                if ((l2tp->conn_id == tunnel_id) &&
                    net_eq(sock_net(sk), net) &&
-                   !(addr && ipv6_addr_equal(addr, laddr)) &&
-                   !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
+                   (!addr || ipv6_addr_equal(addr, laddr)) &&
+                   (!sk->sk_bound_dev_if || !dif ||
+                    sk->sk_bound_dev_if == dif))
                        goto found;
        }
 
@@ -196,16 +197,17 @@ pass_up:
                struct ipv6hdr *iph = ipv6_hdr(skb);
 
                read_lock_bh(&l2tp_ip6_lock);
-               sk = __l2tp_ip6_bind_lookup(net, &iph->daddr,
-                                           0, tunnel_id);
+               sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, inet6_iif(skb),
+                                           tunnel_id);
+               if (!sk) {
+                       read_unlock_bh(&l2tp_ip6_lock);
+                       goto discard;
+               }
+
+               sock_hold(sk);
                read_unlock_bh(&l2tp_ip6_lock);
        }
 
-       if (sk == NULL)
-               goto discard;
-
-       sock_hold(sk);
-
        if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_put;
 
@@ -266,11 +268,10 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr;
        struct net *net = sock_net(sk);
        __be32 v4addr = 0;
+       int bound_dev_if;
        int addr_type;
        int err;
 
-       if (!sock_flag(sk, SOCK_ZAPPED))
-               return -EINVAL;
        if (addr->l2tp_family != AF_INET6)
                return -EINVAL;
        if (addr_len < sizeof(*addr))
@@ -286,41 +287,34 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (addr_type & IPV6_ADDR_MULTICAST)
                return -EADDRNOTAVAIL;
 
-       err = -EADDRINUSE;
-       read_lock_bh(&l2tp_ip6_lock);
-       if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr,
-                                  sk->sk_bound_dev_if, addr->l2tp_conn_id))
-               goto out_in_use;
-       read_unlock_bh(&l2tp_ip6_lock);
-
        lock_sock(sk);
 
        err = -EINVAL;
+       if (!sock_flag(sk, SOCK_ZAPPED))
+               goto out_unlock;
+
        if (sk->sk_state != TCP_CLOSE)
                goto out_unlock;
 
+       bound_dev_if = sk->sk_bound_dev_if;
+
        /* Check if the address belongs to the host. */
        rcu_read_lock();
        if (addr_type != IPV6_ADDR_ANY) {
                struct net_device *dev = NULL;
 
                if (addr_type & IPV6_ADDR_LINKLOCAL) {
-                       if (addr_len >= sizeof(struct sockaddr_in6) &&
-                           addr->l2tp_scope_id) {
-                               /* Override any existing binding, if another
-                                * one is supplied by user.
-                                */
-                               sk->sk_bound_dev_if = addr->l2tp_scope_id;
-                       }
+                       if (addr->l2tp_scope_id)
+                               bound_dev_if = addr->l2tp_scope_id;
 
                        /* Binding to link-local address requires an
-                          interface */
-                       if (!sk->sk_bound_dev_if)
+                        * interface.
+                        */
+                       if (!bound_dev_if)
                                goto out_unlock_rcu;
 
                        err = -ENODEV;
-                       dev = dev_get_by_index_rcu(sock_net(sk),
-                                                  sk->sk_bound_dev_if);
+                       dev = dev_get_by_index_rcu(sock_net(sk), bound_dev_if);
                        if (!dev)
                                goto out_unlock_rcu;
                }
@@ -335,13 +329,22 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        }
        rcu_read_unlock();
 
-       inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
+       write_lock_bh(&l2tp_ip6_lock);
+       if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr, bound_dev_if,
+                                  addr->l2tp_conn_id)) {
+               write_unlock_bh(&l2tp_ip6_lock);
+               err = -EADDRINUSE;
+               goto out_unlock;
+       }
+
+       inet->inet_saddr = v4addr;
+       inet->inet_rcv_saddr = v4addr;
+       sk->sk_bound_dev_if = bound_dev_if;
        sk->sk_v6_rcv_saddr = addr->l2tp_addr;
        np->saddr = addr->l2tp_addr;
 
        l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id;
 
-       write_lock_bh(&l2tp_ip6_lock);
        sk_add_bind_node(sk, &l2tp_ip6_bind_table);
        sk_del_node_init(sk);
        write_unlock_bh(&l2tp_ip6_lock);
@@ -354,10 +357,7 @@ out_unlock_rcu:
        rcu_read_unlock();
 out_unlock:
        release_sock(sk);
-       return err;
 
-out_in_use:
-       read_unlock_bh(&l2tp_ip6_lock);
        return err;
 }
 
@@ -370,9 +370,6 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
        int     addr_type;
        int rc;
 
-       if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
-               return -EINVAL;
-
        if (addr_len < sizeof(*lsa))
                return -EINVAL;
 
@@ -389,10 +386,18 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
                        return -EINVAL;
        }
 
-       rc = ip6_datagram_connect(sk, uaddr, addr_len);
-
        lock_sock(sk);
 
+        /* Must bind first - autobinding does not work */
+       if (sock_flag(sk, SOCK_ZAPPED)) {
+               rc = -EINVAL;
+               goto out_sk;
+       }
+
+       rc = __ip6_datagram_connect(sk, uaddr, addr_len);
+       if (rc < 0)
+               goto out_sk;
+
        l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
 
        write_lock_bh(&l2tp_ip6_lock);
@@ -400,6 +405,7 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
        sk_add_bind_node(sk, &l2tp_ip6_bind_table);
        write_unlock_bh(&l2tp_ip6_lock);
 
+out_sk:
        release_sock(sk);
 
        return rc;
@@ -410,7 +416,7 @@ static int l2tp_ip6_disconnect(struct sock *sk, int flags)
        if (sock_flag(sk, SOCK_ZAPPED))
                return 0;
 
-       return udp_disconnect(sk, flags);
+       return __udp_disconnect(sk, flags);
 }
 
 static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
index 7663c28ba3539f230c9cc5b1bd044164f1ef561c..a4e0d59a40dd52b90f2f54e230600a1633f06831 100644 (file)
 #include "key.h"
 #include "aes_ccm.h"
 
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
-                              u8 *data, size_t data_len, u8 *mic,
-                              size_t mic_len)
+int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+                             u8 *data, size_t data_len, u8 *mic,
+                             size_t mic_len)
 {
        struct scatterlist sg[3];
+       struct aead_request *aead_req;
+       int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
+       u8 *__aad;
 
-       char aead_req_data[sizeof(struct aead_request) +
-                          crypto_aead_reqsize(tfm)]
-               __aligned(__alignof__(struct aead_request));
-       struct aead_request *aead_req = (void *) aead_req_data;
+       aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
+       if (!aead_req)
+               return -ENOMEM;
 
-       memset(aead_req, 0, sizeof(aead_req_data));
+       __aad = (u8 *)aead_req + reqsize;
+       memcpy(__aad, aad, CCM_AAD_LEN);
 
        sg_init_table(sg, 3);
-       sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+       sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
        sg_set_buf(&sg[1], data, data_len);
        sg_set_buf(&sg[2], mic, mic_len);
 
@@ -41,6 +44,9 @@ void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
        aead_request_set_ad(aead_req, sg[0].length);
 
        crypto_aead_encrypt(aead_req);
+       kzfree(aead_req);
+
+       return 0;
 }
 
 int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
@@ -48,18 +54,23 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
                              size_t mic_len)
 {
        struct scatterlist sg[3];
-       char aead_req_data[sizeof(struct aead_request) +
-                          crypto_aead_reqsize(tfm)]
-               __aligned(__alignof__(struct aead_request));
-       struct aead_request *aead_req = (void *) aead_req_data;
+       struct aead_request *aead_req;
+       int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
+       u8 *__aad;
+       int err;
 
        if (data_len == 0)
                return -EINVAL;
 
-       memset(aead_req, 0, sizeof(aead_req_data));
+       aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
+       if (!aead_req)
+               return -ENOMEM;
+
+       __aad = (u8 *)aead_req + reqsize;
+       memcpy(__aad, aad, CCM_AAD_LEN);
 
        sg_init_table(sg, 3);
-       sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+       sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
        sg_set_buf(&sg[1], data, data_len);
        sg_set_buf(&sg[2], mic, mic_len);
 
@@ -67,7 +78,10 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
        aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
        aead_request_set_ad(aead_req, sg[0].length);
 
-       return crypto_aead_decrypt(aead_req);
+       err = crypto_aead_decrypt(aead_req);
+       kzfree(aead_req);
+
+       return err;
 }
 
 struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
index 6a73d1e4d186d34a00da8c2f8e509985c3805607..fcd3254c5cf08d9c61c6bb7ff6f6260922f8c583 100644 (file)
 
 #include <linux/crypto.h>
 
+#define CCM_AAD_LEN    32
+
 struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
                                                    size_t key_len,
                                                    size_t mic_len);
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
-                              u8 *data, size_t data_len, u8 *mic,
-                              size_t mic_len);
+int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+                             u8 *data, size_t data_len, u8 *mic,
+                             size_t mic_len);
 int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
                              u8 *data, size_t data_len, u8 *mic,
                              size_t mic_len);
index 3afe361fd27ca5ef5ac1648106fbe010520fb377..8a4397cc1b08b2ffae5ca09b2a8f927aa090dac1 100644 (file)
 #include "key.h"
 #include "aes_gcm.h"
 
-void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
-                              u8 *data, size_t data_len, u8 *mic)
+int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
+                             u8 *data, size_t data_len, u8 *mic)
 {
        struct scatterlist sg[3];
+       struct aead_request *aead_req;
+       int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
+       u8 *__aad;
 
-       char aead_req_data[sizeof(struct aead_request) +
-                          crypto_aead_reqsize(tfm)]
-               __aligned(__alignof__(struct aead_request));
-       struct aead_request *aead_req = (void *)aead_req_data;
+       aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
+       if (!aead_req)
+               return -ENOMEM;
 
-       memset(aead_req, 0, sizeof(aead_req_data));
+       __aad = (u8 *)aead_req + reqsize;
+       memcpy(__aad, aad, GCM_AAD_LEN);
 
        sg_init_table(sg, 3);
-       sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+       sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
        sg_set_buf(&sg[1], data, data_len);
        sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
 
@@ -37,24 +40,31 @@ void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
        aead_request_set_ad(aead_req, sg[0].length);
 
        crypto_aead_encrypt(aead_req);
+       kzfree(aead_req);
+       return 0;
 }
 
 int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
                              u8 *data, size_t data_len, u8 *mic)
 {
        struct scatterlist sg[3];
-       char aead_req_data[sizeof(struct aead_request) +
-                          crypto_aead_reqsize(tfm)]
-               __aligned(__alignof__(struct aead_request));
-       struct aead_request *aead_req = (void *)aead_req_data;
+       struct aead_request *aead_req;
+       int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
+       u8 *__aad;
+       int err;
 
        if (data_len == 0)
                return -EINVAL;
 
-       memset(aead_req, 0, sizeof(aead_req_data));
+       aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
+       if (!aead_req)
+               return -ENOMEM;
+
+       __aad = (u8 *)aead_req + reqsize;
+       memcpy(__aad, aad, GCM_AAD_LEN);
 
        sg_init_table(sg, 3);
-       sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+       sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
        sg_set_buf(&sg[1], data, data_len);
        sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
 
@@ -63,7 +73,10 @@ int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
                               data_len + IEEE80211_GCMP_MIC_LEN, j_0);
        aead_request_set_ad(aead_req, sg[0].length);
 
-       return crypto_aead_decrypt(aead_req);
+       err = crypto_aead_decrypt(aead_req);
+       kzfree(aead_req);
+
+       return err;
 }
 
 struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
index 1347fda6b76a8890ab5a0e6d902cc6570d551126..55aed5352494fca761f6a30b8c5782ed7effaf10 100644 (file)
 
 #include <linux/crypto.h>
 
-void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
-                              u8 *data, size_t data_len, u8 *mic);
+#define GCM_AAD_LEN    32
+
+int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
+                             u8 *data, size_t data_len, u8 *mic);
 int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
                              u8 *data, size_t data_len, u8 *mic);
 struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
index 3ddd927aaf306acf98a82651a39392a50930e339..bd72a862ddb79f5c0bfd059a3cbf1f1e05f2032d 100644 (file)
 #include "key.h"
 #include "aes_gmac.h"
 
-#define GMAC_MIC_LEN 16
-#define GMAC_NONCE_LEN 12
-#define AAD_LEN 20
-
 int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
                       const u8 *data, size_t data_len, u8 *mic)
 {
        struct scatterlist sg[4];
-       char aead_req_data[sizeof(struct aead_request) +
-                          crypto_aead_reqsize(tfm)]
-               __aligned(__alignof__(struct aead_request));
-       struct aead_request *aead_req = (void *)aead_req_data;
-       u8 zero[GMAC_MIC_LEN], iv[AES_BLOCK_SIZE];
+       u8 *zero, *__aad, iv[AES_BLOCK_SIZE];
+       struct aead_request *aead_req;
+       int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
 
        if (data_len < GMAC_MIC_LEN)
                return -EINVAL;
 
-       memset(aead_req, 0, sizeof(aead_req_data));
+       aead_req = kzalloc(reqsize + GMAC_MIC_LEN + GMAC_AAD_LEN, GFP_ATOMIC);
+       if (!aead_req)
+               return -ENOMEM;
+
+       zero = (u8 *)aead_req + reqsize;
+       __aad = zero + GMAC_MIC_LEN;
+       memcpy(__aad, aad, GMAC_AAD_LEN);
 
-       memset(zero, 0, GMAC_MIC_LEN);
        sg_init_table(sg, 4);
-       sg_set_buf(&sg[0], aad, AAD_LEN);
+       sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN);
        sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN);
        sg_set_buf(&sg[2], zero, GMAC_MIC_LEN);
        sg_set_buf(&sg[3], mic, GMAC_MIC_LEN);
@@ -49,9 +48,10 @@ int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
 
        aead_request_set_tfm(aead_req, tfm);
        aead_request_set_crypt(aead_req, sg, sg, 0, iv);
-       aead_request_set_ad(aead_req, AAD_LEN + data_len);
+       aead_request_set_ad(aead_req, GMAC_AAD_LEN + data_len);
 
        crypto_aead_encrypt(aead_req);
+       kzfree(aead_req);
 
        return 0;
 }
index d328204d73a8a658cc50ab136c0eae5ba82577ec..32e6442c95be4df1af1ee04186f31c20a86c3abc 100644 (file)
 
 #include <linux/crypto.h>
 
+#define GMAC_AAD_LEN   20
+#define GMAC_MIC_LEN   16
+#define GMAC_NONCE_LEN 12
+
 struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
                                                 size_t key_len);
 int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
index c3f610bba3fe9879cb1594e5b1caf00b8a506d6a..eede5c6db8d5a784a27da0c53fc6f34b75dcf0bb 100644 (file)
@@ -820,7 +820,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                    mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
                        break;
                rcu_read_lock();
-               sta = sta_info_get(sdata, mgmt->da);
+               sta = sta_info_get_bss(sdata, mgmt->da);
                rcu_read_unlock();
                if (!sta)
                        return -ENOLINK;
index 6175db385ba7d085f4d2f614697f8ef7e9d914cd..a47bbc973f2dbc629aa8ab6ed91c928784cd26c6 100644 (file)
@@ -2298,6 +2298,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        __le16 fc = hdr->frame_control;
        struct sk_buff_head frame_list;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       struct ethhdr ethhdr;
+       const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
 
        if (unlikely(!ieee80211_is_data(fc)))
                return RX_CONTINUE;
@@ -2308,24 +2310,53 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (!(status->rx_flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
-       if (ieee80211_has_a4(hdr->frame_control) &&
-           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-           !rx->sdata->u.vlan.sta)
-               return RX_DROP_UNUSABLE;
+       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
+               switch (rx->sdata->vif.type) {
+               case NL80211_IFTYPE_AP_VLAN:
+                       if (!rx->sdata->u.vlan.sta)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       if (!rx->sdata->u.mgd.use_4addr)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               default:
+                       return RX_DROP_UNUSABLE;
+               }
+               check_da = NULL;
+               check_sa = NULL;
+       } else switch (rx->sdata->vif.type) {
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
+                       check_da = NULL;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       if (!rx->sta ||
+                           !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
+                               check_sa = NULL;
+                       break;
+               case NL80211_IFTYPE_MESH_POINT:
+                       check_sa = NULL;
+                       break;
+               default:
+                       break;
+       }
 
-       if (is_multicast_ether_addr(hdr->addr1) &&
-           ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-             rx->sdata->u.vlan.sta) ||
-            (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
-             rx->sdata->u.mgd.use_4addr)))
+       if (is_multicast_ether_addr(hdr->addr1))
                return RX_DROP_UNUSABLE;
 
        skb->dev = dev;
        __skb_queue_head_init(&frame_list);
 
+       if (ieee80211_data_to_8023_exthdr(skb, &ethhdr,
+                                         rx->sdata->vif.addr,
+                                         rx->sdata->vif.type))
+               return RX_DROP_UNUSABLE;
+
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
-                                rx->local->hw.extra_tx_headroom, true);
+                                rx->local->hw.extra_tx_headroom,
+                                check_da, check_sa);
 
        while (!skb_queue_empty(&frame_list)) {
                rx->skb = __skb_dequeue(&frame_list);
index 78e9ecbc96e616d0f90228abb5bcda59147ea73f..8e05032689f08677d37942c1549812bfee43cf05 100644 (file)
@@ -688,7 +688,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
        }
 
        /* No need to do anything if the driver does all */
-       if (!local->ops->set_tim)
+       if (ieee80211_hw_check(&local->hw, AP_LINK_PS))
                return;
 
        if (sta->dead)
index 1c56abc496272bb58d71639975e4706c266f2066..bd5f4be89435eb6ef20b7103c7627f7bc10e9cce 100644 (file)
@@ -1501,7 +1501,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
                                struct sta_info *sta,
                                struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct fq *fq = &local->fq;
        struct ieee80211_vif *vif;
        struct txq_info *txqi;
@@ -1526,8 +1525,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
        if (!txqi)
                return false;
 
-       info->control.vif = vif;
-
        spin_lock_bh(&fq->lock);
        ieee80211_txq_enqueue(local, txqi, skb);
        spin_unlock_bh(&fq->lock);
@@ -3213,7 +3210,6 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
 
        if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
-               *ieee80211_get_qos_ctl(hdr) = tid;
                hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
        } else {
                info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
@@ -3338,6 +3334,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
                      (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
        info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
 
+       if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+               tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+               *ieee80211_get_qos_ctl(hdr) = tid;
+       }
+
        __skb_queue_head_init(&tx.skbs);
 
        tx.flags = IEEE80211_TX_UNICAST;
@@ -3426,6 +3427,11 @@ begin:
                goto begin;
        }
 
+       if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
+               info->flags |= IEEE80211_TX_CTL_AMPDU;
+       else
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
        if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
                struct sta_info *sta = container_of(txq->sta, struct sta_info,
                                                    sta);
index ee715764a828954e4c8d90e3bfbcbc697c100ec0..6832bf6ab69fe012ea4eeb3c02b79523083cdc58 100644 (file)
@@ -270,6 +270,22 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
        }
 
+       /*
+        * This is a workaround for VHT-enabled STAs which break the spec
+        * and have the VHT-MCS Rx map filled in with value 3 for all eight
+        * spacial streams, an example is AR9462.
+        *
+        * As per spec, in section 22.1.1 Introduction to the VHT PHY
+        * A VHT STA shall support at least single spactial stream VHT-MCSs
+        * 0 to 7 (transmit and receive) in all supported channel widths.
+        */
+       if (vht_cap->vht_mcs.rx_mcs_map == cpu_to_le16(0xFFFF)) {
+               vht_cap->vht_supported = false;
+               sdata_info(sdata, "Ignoring VHT IE from %pM due to invalid rx_mcs_map\n",
+                          sta->addr);
+               return;
+       }
+
        /* finally set up the bandwidth */
        switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
index b48c1e13e28170edd0202a6bb21c6e2fdb488f47..42ce9bd4426f17aed0b6b50d6298cc01a950b05f 100644 (file)
@@ -405,7 +405,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
        u8 *pos;
        u8 pn[6];
        u64 pn64;
-       u8 aad[2 * AES_BLOCK_SIZE];
+       u8 aad[CCM_AAD_LEN];
        u8 b_0[AES_BLOCK_SIZE];
 
        if (info->control.hw_key &&
@@ -461,10 +461,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
 
        pos += IEEE80211_CCMP_HDR_LEN;
        ccmp_special_blocks(skb, pn, b_0, aad);
-       ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
-                                 skb_put(skb, mic_len), mic_len);
-
-       return 0;
+       return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
+                                        skb_put(skb, mic_len), mic_len);
 }
 
 
@@ -639,7 +637,7 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        u8 *pos;
        u8 pn[6];
        u64 pn64;
-       u8 aad[2 * AES_BLOCK_SIZE];
+       u8 aad[GCM_AAD_LEN];
        u8 j_0[AES_BLOCK_SIZE];
 
        if (info->control.hw_key &&
@@ -696,10 +694,8 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        pos += IEEE80211_GCMP_HDR_LEN;
        gcmp_special_blocks(skb, pn, j_0, aad);
-       ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
-                                 skb_put(skb, IEEE80211_GCMP_MIC_LEN));
-
-       return 0;
+       return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
+                                        skb_put(skb, IEEE80211_GCMP_MIC_LEN));
 }
 
 ieee80211_tx_result
@@ -1123,9 +1119,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx)
        struct ieee80211_key *key = tx->key;
        struct ieee80211_mmie_16 *mmie;
        struct ieee80211_hdr *hdr;
-       u8 aad[20];
+       u8 aad[GMAC_AAD_LEN];
        u64 pn64;
-       u8 nonce[12];
+       u8 nonce[GMAC_NONCE_LEN];
 
        if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
                return TX_DROP;
@@ -1171,7 +1167,7 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx)
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_key *key = rx->key;
        struct ieee80211_mmie_16 *mmie;
-       u8 aad[20], mic[16], ipn[6], nonce[12];
+       u8 aad[GMAC_AAD_LEN], mic[GMAC_MIC_LEN], ipn[6], nonce[GMAC_NONCE_LEN];
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
        if (!ieee80211_is_mgmt(hdr->frame_control))
index 0e4334cbde17519cf69bbc099127c0d81a626467..15fe97644ffe048c9b1d5818c0b1aec56eb988f4 100644 (file)
@@ -1252,7 +1252,7 @@ static int rtm_to_route_config(struct sk_buff *skb,  struct nlmsghdr *nlh,
                if (!nla)
                        continue;
 
-               switch(index) {
+               switch (index) {
                case RTA_OIF:
                        cfg->rc_ifindex = nla_get_u32(nla);
                        break;
index 13290a70fa714f0c0ce7083c223d835da04d77d8..1308a56f259149e7aee910f5e84dfe3e14819ec9 100644 (file)
@@ -246,6 +246,7 @@ enum {
        ncsi_dev_state_config_gls,
        ncsi_dev_state_config_done,
        ncsi_dev_state_suspend_select   = 0x0401,
+       ncsi_dev_state_suspend_gls,
        ncsi_dev_state_suspend_dcnt,
        ncsi_dev_state_suspend_dc,
        ncsi_dev_state_suspend_deselect,
@@ -264,6 +265,7 @@ struct ncsi_dev_priv {
 #endif
        unsigned int        package_num;     /* Number of packages         */
        struct list_head    packages;        /* List of packages           */
+       struct ncsi_channel *hot_channel;    /* Channel was ever active    */
        struct ncsi_request requests[256];   /* Request table              */
        unsigned int        request_id;      /* Last used request ID       */
 #define NCSI_REQ_START_IDX     1
index b41a6617d4980de34604c7a2d6db5047a5029126..6898e7229285a6720115a37d58673f569d4a9bff 100644 (file)
@@ -141,23 +141,35 @@ static int ncsi_aen_handler_hncdsc(struct ncsi_dev_priv *ndp,
                return -ENODEV;
 
        /* If the channel is active one, we need reconfigure it */
+       spin_lock_irqsave(&nc->lock, flags);
        ncm = &nc->modes[NCSI_MODE_LINK];
        hncdsc = (struct ncsi_aen_hncdsc_pkt *)h;
        ncm->data[3] = ntohl(hncdsc->status);
        if (!list_empty(&nc->link) ||
-           nc->state != NCSI_CHANNEL_ACTIVE ||
-           (ncm->data[3] & 0x1))
+           nc->state != NCSI_CHANNEL_ACTIVE) {
+               spin_unlock_irqrestore(&nc->lock, flags);
                return 0;
+       }
 
-       if (ndp->flags & NCSI_DEV_HWA)
+       spin_unlock_irqrestore(&nc->lock, flags);
+       if (!(ndp->flags & NCSI_DEV_HWA) && !(ncm->data[3] & 0x1))
                ndp->flags |= NCSI_DEV_RESHUFFLE;
 
        /* If this channel is the active one and the link doesn't
         * work, we have to choose another channel to be active one.
         * The logic here is exactly similar to what we do when link
         * is down on the active channel.
+        *
+        * On the other hand, we need configure it when host driver
+        * state on the active channel becomes ready.
         */
        ncsi_stop_channel_monitor(nc);
+
+       spin_lock_irqsave(&nc->lock, flags);
+       nc->state = (ncm->data[3] & 0x1) ? NCSI_CHANNEL_INACTIVE :
+                                          NCSI_CHANNEL_ACTIVE;
+       spin_unlock_irqrestore(&nc->lock, flags);
+
        spin_lock_irqsave(&ndp->lock, flags);
        list_add_tail_rcu(&nc->link, &ndp->channel_queue);
        spin_unlock_irqrestore(&ndp->lock, flags);
index 5e509e547c2ddf1867639e01541eb37b1348d663..a3bd5fa8ad093a3fb7533f00186111bf9a19c2ed 100644 (file)
@@ -540,42 +540,86 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
                nd->state = ncsi_dev_state_suspend_select;
                /* Fall through */
        case ncsi_dev_state_suspend_select:
-       case ncsi_dev_state_suspend_dcnt:
-       case ncsi_dev_state_suspend_dc:
-       case ncsi_dev_state_suspend_deselect:
                ndp->pending_req_num = 1;
 
-               np = ndp->active_package;
-               nc = ndp->active_channel;
+               nca.type = NCSI_PKT_CMD_SP;
                nca.package = np->id;
-               if (nd->state == ncsi_dev_state_suspend_select) {
-                       nca.type = NCSI_PKT_CMD_SP;
-                       nca.channel = NCSI_RESERVED_CHANNEL;
-                       if (ndp->flags & NCSI_DEV_HWA)
-                               nca.bytes[0] = 0;
-                       else
-                               nca.bytes[0] = 1;
+               nca.channel = NCSI_RESERVED_CHANNEL;
+               if (ndp->flags & NCSI_DEV_HWA)
+                       nca.bytes[0] = 0;
+               else
+                       nca.bytes[0] = 1;
+
+               /* To retrieve the last link states of channels in current
+                * package when current active channel needs fail over to
+                * another one. It means we will possibly select another
+                * channel as next active one. The link states of channels
+                * are most important factor of the selection. So we need
+                * accurate link states. Unfortunately, the link states on
+                * inactive channels can't be updated with LSC AEN in time.
+                */
+               if (ndp->flags & NCSI_DEV_RESHUFFLE)
+                       nd->state = ncsi_dev_state_suspend_gls;
+               else
                        nd->state = ncsi_dev_state_suspend_dcnt;
-               } else if (nd->state == ncsi_dev_state_suspend_dcnt) {
-                       nca.type = NCSI_PKT_CMD_DCNT;
-                       nca.channel = nc->id;
-                       nd->state = ncsi_dev_state_suspend_dc;
-               } else if (nd->state == ncsi_dev_state_suspend_dc) {
-                       nca.type = NCSI_PKT_CMD_DC;
+               ret = ncsi_xmit_cmd(&nca);
+               if (ret)
+                       goto error;
+
+               break;
+       case ncsi_dev_state_suspend_gls:
+               ndp->pending_req_num = np->channel_num;
+
+               nca.type = NCSI_PKT_CMD_GLS;
+               nca.package = np->id;
+
+               nd->state = ncsi_dev_state_suspend_dcnt;
+               NCSI_FOR_EACH_CHANNEL(np, nc) {
                        nca.channel = nc->id;
-                       nca.bytes[0] = 1;
-                       nd->state = ncsi_dev_state_suspend_deselect;
-               } else if (nd->state == ncsi_dev_state_suspend_deselect) {
-                       nca.type = NCSI_PKT_CMD_DP;
-                       nca.channel = NCSI_RESERVED_CHANNEL;
-                       nd->state = ncsi_dev_state_suspend_done;
+                       ret = ncsi_xmit_cmd(&nca);
+                       if (ret)
+                               goto error;
                }
 
+               break;
+       case ncsi_dev_state_suspend_dcnt:
+               ndp->pending_req_num = 1;
+
+               nca.type = NCSI_PKT_CMD_DCNT;
+               nca.package = np->id;
+               nca.channel = nc->id;
+
+               nd->state = ncsi_dev_state_suspend_dc;
                ret = ncsi_xmit_cmd(&nca);
-               if (ret) {
-                       nd->state = ncsi_dev_state_functional;
-                       return;
-               }
+               if (ret)
+                       goto error;
+
+               break;
+       case ncsi_dev_state_suspend_dc:
+               ndp->pending_req_num = 1;
+
+               nca.type = NCSI_PKT_CMD_DC;
+               nca.package = np->id;
+               nca.channel = nc->id;
+               nca.bytes[0] = 1;
+
+               nd->state = ncsi_dev_state_suspend_deselect;
+               ret = ncsi_xmit_cmd(&nca);
+               if (ret)
+                       goto error;
+
+               break;
+       case ncsi_dev_state_suspend_deselect:
+               ndp->pending_req_num = 1;
+
+               nca.type = NCSI_PKT_CMD_DP;
+               nca.package = np->id;
+               nca.channel = NCSI_RESERVED_CHANNEL;
+
+               nd->state = ncsi_dev_state_suspend_done;
+               ret = ncsi_xmit_cmd(&nca);
+               if (ret)
+                       goto error;
 
                break;
        case ncsi_dev_state_suspend_done:
@@ -589,6 +633,10 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
                netdev_warn(nd->dev, "Wrong NCSI state 0x%x in suspend\n",
                            nd->state);
        }
+
+       return;
+error:
+       nd->state = ncsi_dev_state_functional;
 }
 
 static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
@@ -597,6 +645,7 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
        struct net_device *dev = nd->dev;
        struct ncsi_package *np = ndp->active_package;
        struct ncsi_channel *nc = ndp->active_channel;
+       struct ncsi_channel *hot_nc = NULL;
        struct ncsi_cmd_arg nca;
        unsigned char index;
        unsigned long flags;
@@ -702,12 +751,20 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
                break;
        case ncsi_dev_state_config_done:
                spin_lock_irqsave(&nc->lock, flags);
-               if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1)
+               if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
+                       hot_nc = nc;
                        nc->state = NCSI_CHANNEL_ACTIVE;
-               else
+               } else {
+                       hot_nc = NULL;
                        nc->state = NCSI_CHANNEL_INACTIVE;
+               }
                spin_unlock_irqrestore(&nc->lock, flags);
 
+               /* Update the hot channel */
+               spin_lock_irqsave(&ndp->lock, flags);
+               ndp->hot_channel = hot_nc;
+               spin_unlock_irqrestore(&ndp->lock, flags);
+
                ncsi_start_channel_monitor(nc);
                ncsi_process_next_channel(ndp);
                break;
@@ -725,10 +782,14 @@ error:
 static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
 {
        struct ncsi_package *np;
-       struct ncsi_channel *nc, *found;
+       struct ncsi_channel *nc, *found, *hot_nc;
        struct ncsi_channel_mode *ncm;
        unsigned long flags;
 
+       spin_lock_irqsave(&ndp->lock, flags);
+       hot_nc = ndp->hot_channel;
+       spin_unlock_irqrestore(&ndp->lock, flags);
+
        /* The search is done once an inactive channel with up
         * link is found.
         */
@@ -746,6 +807,9 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
                        if (!found)
                                found = nc;
 
+                       if (nc == hot_nc)
+                               found = nc;
+
                        ncm = &nc->modes[NCSI_MODE_LINK];
                        if (ncm->data[2] & 0x1) {
                                spin_unlock_irqrestore(&nc->lock, flags);
index fcb5d1df11e99b61351e8e381626c96e6ee1820b..004af030ef1abcdf554467f60a350649e205d80e 100644 (file)
@@ -361,16 +361,9 @@ next_hook:
                if (ret == 0)
                        ret = -EPERM;
        } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
-               int err;
-
-               RCU_INIT_POINTER(state->hook_entries, entry);
-               err = nf_queue(skb, state, verdict >> NF_VERDICT_QBITS);
-               if (err < 0) {
-                       if (err == -ESRCH &&
-                          (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
-                               goto next_hook;
-                       kfree_skb(skb);
-               }
+               ret = nf_queue(skb, state, &entry, verdict);
+               if (ret == 1 && entry)
+                       goto next_hook;
        }
        return ret;
 }
index c3c809b2e7122daabac5b45ffed67979e0fecb28..a6e44ef2ec9a97dfd23ced452f2ec260e57f884c 100644 (file)
@@ -2845,7 +2845,7 @@ static struct genl_family ip_vs_genl_family = {
        .hdrsize        = 0,
        .name           = IPVS_GENL_NAME,
        .version        = IPVS_GENL_VERSION,
-       .maxattr        = IPVS_CMD_MAX,
+       .maxattr        = IPVS_CMD_ATTR_MAX,
        .netnsok        = true,         /* Make ipvsadm to work on netns */
 };
 
index 1b07578bedf336c53e3b6072c8c3324f7f18081b..9350530c16c1b0e9524591945214fc8775e5a9e6 100644 (file)
@@ -283,6 +283,7 @@ struct ip_vs_sync_buff {
  */
 static void ntoh_seq(struct ip_vs_seq *no, struct ip_vs_seq *ho)
 {
+       memset(ho, 0, sizeof(*ho));
        ho->init_seq       = get_unaligned_be32(&no->init_seq);
        ho->delta          = get_unaligned_be32(&no->delta);
        ho->previous_delta = get_unaligned_be32(&no->previous_delta);
@@ -917,8 +918,10 @@ static void ip_vs_proc_conn(struct netns_ipvs *ipvs, struct ip_vs_conn_param *pa
                        kfree(param->pe_data);
        }
 
-       if (opt)
-               memcpy(&cp->in_seq, opt, sizeof(*opt));
+       if (opt) {
+               cp->in_seq = opt->in_seq;
+               cp->out_seq = opt->out_seq;
+       }
        atomic_set(&cp->in_pkts, sysctl_sync_threshold(ipvs));
        cp->state = state;
        cp->old_state = cp->state;
index ba6a1d4212225f5ff735eed006e12b3a244a5076..0f87e5d21be7161f6d885fd3ab40f1e752e68a66 100644 (file)
@@ -76,6 +76,7 @@ struct conntrack_gc_work {
        struct delayed_work     dwork;
        u32                     last_bucket;
        bool                    exiting;
+       long                    next_gc_run;
 };
 
 static __read_mostly struct kmem_cache *nf_conntrack_cachep;
@@ -83,9 +84,11 @@ static __read_mostly spinlock_t nf_conntrack_locks_all_lock;
 static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock);
 static __read_mostly bool nf_conntrack_locks_all;
 
+/* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */
 #define GC_MAX_BUCKETS_DIV     64u
-#define GC_MAX_BUCKETS         8192u
-#define GC_INTERVAL            (5 * HZ)
+/* upper bound of scan intervals */
+#define GC_INTERVAL_MAX                (2 * HZ)
+/* maximum conntracks to evict per gc run */
 #define GC_MAX_EVICTS          256u
 
 static struct conntrack_gc_work conntrack_gc_work;
@@ -936,13 +939,13 @@ static noinline int early_drop(struct net *net, unsigned int _hash)
 static void gc_worker(struct work_struct *work)
 {
        unsigned int i, goal, buckets = 0, expired_count = 0;
-       unsigned long next_run = GC_INTERVAL;
-       unsigned int ratio, scanned = 0;
        struct conntrack_gc_work *gc_work;
+       unsigned int ratio, scanned = 0;
+       unsigned long next_run;
 
        gc_work = container_of(work, struct conntrack_gc_work, dwork.work);
 
-       goal = min(nf_conntrack_htable_size / GC_MAX_BUCKETS_DIV, GC_MAX_BUCKETS);
+       goal = nf_conntrack_htable_size / GC_MAX_BUCKETS_DIV;
        i = gc_work->last_bucket;
 
        do {
@@ -982,17 +985,47 @@ static void gc_worker(struct work_struct *work)
        if (gc_work->exiting)
                return;
 
+       /*
+        * Eviction will normally happen from the packet path, and not
+        * from this gc worker.
+        *
+        * This worker is only here to reap expired entries when system went
+        * idle after a busy period.
+        *
+        * The heuristics below are supposed to balance conflicting goals:
+        *
+        * 1. Minimize time until we notice a stale entry
+        * 2. Maximize scan intervals to not waste cycles
+        *
+        * Normally, expired_count will be 0, this increases the next_run time
+        * to priorize 2) above.
+        *
+        * As soon as a timed-out entry is found, move towards 1) and increase
+        * the scan frequency.
+        * In case we have lots of evictions next scan is done immediately.
+        */
        ratio = scanned ? expired_count * 100 / scanned : 0;
-       if (ratio >= 90)
+       if (ratio >= 90 || expired_count == GC_MAX_EVICTS) {
+               gc_work->next_gc_run = 0;
                next_run = 0;
+       } else if (expired_count) {
+               gc_work->next_gc_run /= 2U;
+               next_run = msecs_to_jiffies(1);
+       } else {
+               if (gc_work->next_gc_run < GC_INTERVAL_MAX)
+                       gc_work->next_gc_run += msecs_to_jiffies(1);
+
+               next_run = gc_work->next_gc_run;
+       }
 
        gc_work->last_bucket = i;
-       schedule_delayed_work(&gc_work->dwork, next_run);
+       queue_delayed_work(system_long_wq, &gc_work->dwork, next_run);
 }
 
 static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work)
 {
        INIT_DELAYED_WORK(&gc_work->dwork, gc_worker);
+       gc_work->next_gc_run = GC_INTERVAL_MAX;
        gc_work->exiting = false;
 }
 
@@ -1885,7 +1918,7 @@ int nf_conntrack_init_start(void)
        nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
 
        conntrack_gc_work_init(&conntrack_gc_work);
-       schedule_delayed_work(&conntrack_gc_work.dwork, GC_INTERVAL);
+       queue_delayed_work(system_long_wq, &conntrack_gc_work.dwork, GC_INTERVAL_MAX);
 
        return 0;
 
index 336e21559e011d4f0fe154934ecf7d5a765aefdd..7341adf7059d3232f458bc02528d9631107ebfce 100644 (file)
@@ -138,9 +138,14 @@ __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
 
        for (i = 0; i < nf_ct_helper_hsize; i++) {
                hlist_for_each_entry_rcu(h, &nf_ct_helper_hash[i], hnode) {
-                       if (!strcmp(h->name, name) &&
-                           h->tuple.src.l3num == l3num &&
-                           h->tuple.dst.protonum == protonum)
+                       if (strcmp(h->name, name))
+                               continue;
+
+                       if (h->tuple.src.l3num != NFPROTO_UNSPEC &&
+                           h->tuple.src.l3num != l3num)
+                               continue;
+
+                       if (h->tuple.dst.protonum == protonum)
                                return h;
                }
        }
index 621b81c7bddc5d486dff5cff77c4070a41edda36..c3fc14e021ecf55ba9085cd7ee7a86bfc5352750 100644 (file)
@@ -1436,9 +1436,12 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
                handler = &sip_handlers[i];
                if (handler->request == NULL)
                        continue;
-               if (*datalen < handler->len ||
+               if (*datalen < handler->len + 2 ||
                    strncasecmp(*dptr, handler->method, handler->len))
                        continue;
+               if ((*dptr)[handler->len] != ' ' ||
+                   !isalpha((*dptr)[handler->len+1]))
+                       continue;
 
                if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
                                      &matchoff, &matchlen) <= 0) {
index e0adb5959342148d9501a48f6bb92b90d2566c00..9fdb655f85bc15fe6b0566f25f876a5561cbc576 100644 (file)
@@ -18,7 +18,7 @@ unsigned int nf_iterate(struct sk_buff *skb, struct nf_hook_state *state,
 
 /* nf_queue.c */
 int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
-            unsigned int queuenum);
+            struct nf_hook_entry **entryp, unsigned int verdict);
 void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry);
 int __init netfilter_queue_init(void);
 
index bbb8f3df79f723d544824c2ce49c9bc1095d9276..5b9c884a452e8305e9d3ff0a420887bd7f5e4dd2 100644 (file)
@@ -42,7 +42,7 @@ struct nf_nat_conn_key {
        const struct nf_conntrack_zone *zone;
 };
 
-static struct rhashtable nf_nat_bysource_table;
+static struct rhltable nf_nat_bysource_table;
 
 inline const struct nf_nat_l3proto *
 __nf_nat_l3proto_find(u8 family)
@@ -193,9 +193,12 @@ static int nf_nat_bysource_cmp(struct rhashtable_compare_arg *arg,
        const struct nf_nat_conn_key *key = arg->key;
        const struct nf_conn *ct = obj;
 
-       return same_src(ct, key->tuple) &&
-              net_eq(nf_ct_net(ct), key->net) &&
-              nf_ct_zone_equal(ct, key->zone, IP_CT_DIR_ORIGINAL);
+       if (!same_src(ct, key->tuple) ||
+           !net_eq(nf_ct_net(ct), key->net) ||
+           !nf_ct_zone_equal(ct, key->zone, IP_CT_DIR_ORIGINAL))
+               return 1;
+
+       return 0;
 }
 
 static struct rhashtable_params nf_nat_bysource_params = {
@@ -204,7 +207,6 @@ static struct rhashtable_params nf_nat_bysource_params = {
        .obj_cmpfn = nf_nat_bysource_cmp,
        .nelem_hint = 256,
        .min_size = 1024,
-       .nulls_base = (1U << RHT_BASE_SHIFT),
 };
 
 /* Only called for SRC manip */
@@ -223,12 +225,15 @@ find_appropriate_src(struct net *net,
                .tuple = tuple,
                .zone = zone
        };
+       struct rhlist_head *hl;
 
-       ct = rhashtable_lookup_fast(&nf_nat_bysource_table, &key,
-                                   nf_nat_bysource_params);
-       if (!ct)
+       hl = rhltable_lookup(&nf_nat_bysource_table, &key,
+                            nf_nat_bysource_params);
+       if (!hl)
                return 0;
 
+       ct = container_of(hl, typeof(*ct), nat_bysource);
+
        nf_ct_invert_tuplepr(result,
                             &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
        result->dst = tuple->dst;
@@ -446,11 +451,17 @@ nf_nat_setup_info(struct nf_conn *ct,
        }
 
        if (maniptype == NF_NAT_MANIP_SRC) {
+               struct nf_nat_conn_key key = {
+                       .net = nf_ct_net(ct),
+                       .tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+                       .zone = nf_ct_zone(ct),
+               };
                int err;
 
-               err = rhashtable_insert_fast(&nf_nat_bysource_table,
-                                            &ct->nat_bysource,
-                                            nf_nat_bysource_params);
+               err = rhltable_insert_key(&nf_nat_bysource_table,
+                                         &key,
+                                         &ct->nat_bysource,
+                                         nf_nat_bysource_params);
                if (err)
                        return NF_DROP;
        }
@@ -567,8 +578,8 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
         * will delete entry from already-freed table.
         */
        ct->status &= ~IPS_NAT_DONE_MASK;
-       rhashtable_remove_fast(&nf_nat_bysource_table, &ct->nat_bysource,
-                              nf_nat_bysource_params);
+       rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource,
+                       nf_nat_bysource_params);
 
        /* don't delete conntrack.  Although that would make things a lot
         * simpler, we'd end up flushing all conntracks on nat rmmod.
@@ -698,8 +709,8 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
        if (!nat)
                return;
 
-       rhashtable_remove_fast(&nf_nat_bysource_table, &ct->nat_bysource,
-                              nf_nat_bysource_params);
+       rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource,
+                       nf_nat_bysource_params);
 }
 
 static struct nf_ct_ext_type nat_extend __read_mostly = {
@@ -834,13 +845,13 @@ static int __init nf_nat_init(void)
 {
        int ret;
 
-       ret = rhashtable_init(&nf_nat_bysource_table, &nf_nat_bysource_params);
+       ret = rhltable_init(&nf_nat_bysource_table, &nf_nat_bysource_params);
        if (ret)
                return ret;
 
        ret = nf_ct_extend_register(&nat_extend);
        if (ret < 0) {
-               rhashtable_destroy(&nf_nat_bysource_table);
+               rhltable_destroy(&nf_nat_bysource_table);
                printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
                return ret;
        }
@@ -864,7 +875,7 @@ static int __init nf_nat_init(void)
        return 0;
 
  cleanup_extend:
-       rhashtable_destroy(&nf_nat_bysource_table);
+       rhltable_destroy(&nf_nat_bysource_table);
        nf_ct_extend_unregister(&nat_extend);
        return ret;
 }
@@ -883,7 +894,7 @@ static void __exit nf_nat_cleanup(void)
        for (i = 0; i < NFPROTO_NUMPROTO; i++)
                kfree(nf_nat_l4protos[i]);
 
-       rhashtable_destroy(&nf_nat_bysource_table);
+       rhltable_destroy(&nf_nat_bysource_table);
 }
 
 MODULE_LICENSE("GPL");
index 96964a0070e11da46aa97b3fe94fb4f778e40418..8f08d759844a9ab9eb24bf28a6f144e1207ad955 100644 (file)
@@ -107,13 +107,8 @@ void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry)
        rcu_read_unlock();
 }
 
-/*
- * Any packet that leaves via this function must come back
- * through nf_reinject().
- */
-int nf_queue(struct sk_buff *skb,
-            struct nf_hook_state *state,
-            unsigned int queuenum)
+static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
+                     unsigned int queuenum)
 {
        int status = -ENOENT;
        struct nf_queue_entry *entry = NULL;
@@ -161,6 +156,27 @@ err:
        return status;
 }
 
+/* Packets leaving via this function must come back through nf_reinject(). */
+int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
+            struct nf_hook_entry **entryp, unsigned int verdict)
+{
+       struct nf_hook_entry *entry = *entryp;
+       int ret;
+
+       RCU_INIT_POINTER(state->hook_entries, entry);
+       ret = __nf_queue(skb, state, verdict >> NF_VERDICT_QBITS);
+       if (ret < 0) {
+               if (ret == -ESRCH &&
+                   (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) {
+                       *entryp = rcu_dereference(entry->next);
+                       return 1;
+               }
+               kfree_skb(skb);
+       }
+
+       return 0;
+}
+
 void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 {
        struct nf_hook_entry *hook_entry;
@@ -187,26 +203,26 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
        entry->state.thresh = INT_MIN;
 
        if (verdict == NF_ACCEPT) {
-       next_hook:
-               verdict = nf_iterate(skb, &entry->state, &hook_entry);
+               hook_entry = rcu_dereference(hook_entry->next);
+               if (hook_entry)
+next_hook:
+                       verdict = nf_iterate(skb, &entry->state, &hook_entry);
        }
 
        switch (verdict & NF_VERDICT_MASK) {
        case NF_ACCEPT:
        case NF_STOP:
+okfn:
                local_bh_disable();
                entry->state.okfn(entry->state.net, entry->state.sk, skb);
                local_bh_enable();
                break;
        case NF_QUEUE:
-               RCU_INIT_POINTER(entry->state.hook_entries, hook_entry);
-               err = nf_queue(skb, &entry->state,
-                              verdict >> NF_VERDICT_QBITS);
-               if (err < 0) {
-                       if (err == -ESRCH &&
-                          (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
+               err = nf_queue(skb, &entry->state, &hook_entry, verdict);
+               if (err == 1) {
+                       if (hook_entry)
                                goto next_hook;
-                       kfree_skb(skb);
+                       goto okfn;
                }
                break;
        case NF_STOLEN:
index b70d3ea1430e7db49c4a4fc86f87dbb47cfdbe8c..e5194f6f906cb28396620917968aae42fb0872b2 100644 (file)
@@ -2570,7 +2570,8 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
        }
 
        if (set->timeout &&
-           nla_put_be64(skb, NFTA_SET_TIMEOUT, cpu_to_be64(set->timeout),
+           nla_put_be64(skb, NFTA_SET_TIMEOUT,
+                        cpu_to_be64(jiffies_to_msecs(set->timeout)),
                         NFTA_SET_PAD))
                goto nla_put_failure;
        if (set->gc_int &&
@@ -2859,7 +2860,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
        if (nla[NFTA_SET_TIMEOUT] != NULL) {
                if (!(flags & NFT_SET_TIMEOUT))
                        return -EINVAL;
-               timeout = be64_to_cpu(nla_get_be64(nla[NFTA_SET_TIMEOUT]));
+               timeout = msecs_to_jiffies(be64_to_cpu(nla_get_be64(
+                                               nla[NFTA_SET_TIMEOUT])));
        }
        gc_int = 0;
        if (nla[NFTA_SET_GC_INTERVAL] != NULL) {
@@ -2956,12 +2958,14 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
 
        err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
        if (err < 0)
-               goto err2;
+               goto err3;
 
        list_add_tail_rcu(&set->list, &table->sets);
        table->use++;
        return 0;
 
+err3:
+       ops->destroy(set);
 err2:
        kfree(set);
 err1:
@@ -3176,7 +3180,8 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
 
        if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
            nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
-                        cpu_to_be64(*nft_set_ext_timeout(ext)),
+                        cpu_to_be64(jiffies_to_msecs(
+                                               *nft_set_ext_timeout(ext))),
                         NFTA_SET_ELEM_PAD))
                goto nla_put_failure;
 
@@ -3445,21 +3450,22 @@ void *nft_set_elem_init(const struct nft_set *set,
                memcpy(nft_set_ext_data(ext), data, set->dlen);
        if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION))
                *nft_set_ext_expiration(ext) =
-                       jiffies + msecs_to_jiffies(timeout);
+                       jiffies + timeout;
        if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT))
                *nft_set_ext_timeout(ext) = timeout;
 
        return elem;
 }
 
-void nft_set_elem_destroy(const struct nft_set *set, void *elem)
+void nft_set_elem_destroy(const struct nft_set *set, void *elem,
+                         bool destroy_expr)
 {
        struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
 
        nft_data_uninit(nft_set_ext_key(ext), NFT_DATA_VALUE);
        if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
                nft_data_uninit(nft_set_ext_data(ext), set->dtype);
-       if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
+       if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
                nf_tables_expr_destroy(NULL, nft_set_ext_expr(ext));
 
        kfree(elem);
@@ -3532,7 +3538,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        if (nla[NFTA_SET_ELEM_TIMEOUT] != NULL) {
                if (!(set->flags & NFT_SET_TIMEOUT))
                        return -EINVAL;
-               timeout = be64_to_cpu(nla_get_be64(nla[NFTA_SET_ELEM_TIMEOUT]));
+               timeout = msecs_to_jiffies(be64_to_cpu(nla_get_be64(
+                                       nla[NFTA_SET_ELEM_TIMEOUT])));
        } else if (set->flags & NFT_SET_TIMEOUT) {
                timeout = set->timeout;
        }
@@ -3565,6 +3572,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                dreg = nft_type_to_reg(set->dtype);
                list_for_each_entry(binding, &set->bindings, list) {
                        struct nft_ctx bind_ctx = {
+                               .net    = ctx->net,
                                .afi    = ctx->afi,
                                .table  = ctx->table,
                                .chain  = (struct nft_chain *)binding->chain,
@@ -3812,7 +3820,7 @@ void nft_set_gc_batch_release(struct rcu_head *rcu)
 
        gcb = container_of(rcu, struct nft_set_gc_batch, head.rcu);
        for (i = 0; i < gcb->head.cnt; i++)
-               nft_set_elem_destroy(gcb->head.set, gcb->elems[i]);
+               nft_set_elem_destroy(gcb->head.set, gcb->elems[i], true);
        kfree(gcb);
 }
 EXPORT_SYMBOL_GPL(nft_set_gc_batch_release);
@@ -4030,7 +4038,7 @@ static void nf_tables_commit_release(struct nft_trans *trans)
                break;
        case NFT_MSG_DELSETELEM:
                nft_set_elem_destroy(nft_trans_elem_set(trans),
-                                    nft_trans_elem(trans).priv);
+                                    nft_trans_elem(trans).priv, true);
                break;
        }
        kfree(trans);
@@ -4171,7 +4179,7 @@ static void nf_tables_abort_release(struct nft_trans *trans)
                break;
        case NFT_MSG_NEWSETELEM:
                nft_set_elem_destroy(nft_trans_elem_set(trans),
-                                    nft_trans_elem(trans).priv);
+                                    nft_trans_elem(trans).priv, true);
                break;
        }
        kfree(trans);
@@ -4421,9 +4429,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
  *     Otherwise a 0 is returned and the attribute value is stored in the
  *     destination variable.
  */
-unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest)
+int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest)
 {
-       int val;
+       u32 val;
 
        val = ntohl(nla_get_be32(attr));
        if (val > max)
index e3b83c31da2e56ee9932d4d3d22dc8acfd87a617..31ca94793aa9622f4a77ab852c3a8c1a422ba658 100644 (file)
@@ -44,18 +44,22 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
                                 &regs->data[priv->sreg_key],
                                 &regs->data[priv->sreg_data],
                                 timeout, GFP_ATOMIC);
-       if (elem == NULL) {
-               if (set->size)
-                       atomic_dec(&set->nelems);
-               return NULL;
-       }
+       if (elem == NULL)
+               goto err1;
 
        ext = nft_set_elem_ext(set, elem);
        if (priv->expr != NULL &&
            nft_expr_clone(nft_set_ext_expr(ext), priv->expr) < 0)
-               return NULL;
+               goto err2;
 
        return elem;
+
+err2:
+       nft_set_elem_destroy(set, elem, false);
+err1:
+       if (set->size)
+               atomic_dec(&set->nelems);
+       return NULL;
 }
 
 static void nft_dynset_eval(const struct nft_expr *expr,
@@ -139,6 +143,9 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                        return PTR_ERR(set);
        }
 
+       if (set->ops->update == NULL)
+               return -EOPNOTSUPP;
+
        if (set->flags & NFT_SET_CONSTANT)
                return -EBUSY;
 
@@ -158,7 +165,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
        if (tb[NFTA_DYNSET_TIMEOUT] != NULL) {
                if (!(set->flags & NFT_SET_TIMEOUT))
                        return -EINVAL;
-               timeout = be64_to_cpu(nla_get_be64(tb[NFTA_DYNSET_TIMEOUT]));
+               timeout = msecs_to_jiffies(be64_to_cpu(nla_get_be64(
+                                               tb[NFTA_DYNSET_TIMEOUT])));
        }
 
        priv->sreg_key = nft_parse_register(tb[NFTA_DYNSET_SREG_KEY]);
@@ -246,7 +254,8 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_DYNSET_SET_NAME, priv->set->name))
                goto nla_put_failure;
-       if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT, cpu_to_be64(priv->timeout),
+       if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT,
+                        cpu_to_be64(jiffies_to_msecs(priv->timeout)),
                         NFTA_DYNSET_PAD))
                goto nla_put_failure;
        if (priv->expr && nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr))
index a84cf3d6605661aa8bb8966e226a79ea1b63786a..47beb3abcc9daf46e084c0f189eaf7091d11241e 100644 (file)
@@ -59,7 +59,8 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_exthdr *priv = nft_expr_priv(expr);
-       u32 offset, len, err;
+       u32 offset, len;
+       int err;
 
        if (tb[NFTA_EXTHDR_DREG] == NULL ||
            tb[NFTA_EXTHDR_TYPE] == NULL ||
index 09473b415b95b281c3264cda23d446dd5a3d56ab..d5447a22275c0649cb125364730986a52436816d 100644 (file)
@@ -44,6 +44,7 @@ static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
        [NFTA_HASH_LEN]         = { .type = NLA_U32 },
        [NFTA_HASH_MODULUS]     = { .type = NLA_U32 },
        [NFTA_HASH_SEED]        = { .type = NLA_U32 },
+       [NFTA_HASH_OFFSET]      = { .type = NLA_U32 },
 };
 
 static int nft_hash_init(const struct nft_ctx *ctx,
@@ -52,6 +53,7 @@ static int nft_hash_init(const struct nft_ctx *ctx,
 {
        struct nft_hash *priv = nft_expr_priv(expr);
        u32 len;
+       int err;
 
        if (!tb[NFTA_HASH_SREG] ||
            !tb[NFTA_HASH_DREG] ||
@@ -66,8 +68,10 @@ static int nft_hash_init(const struct nft_ctx *ctx,
        priv->sreg = nft_parse_register(tb[NFTA_HASH_SREG]);
        priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
 
-       len = ntohl(nla_get_be32(tb[NFTA_HASH_LEN]));
-       if (len == 0 || len > U8_MAX)
+       err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len);
+       if (err < 0)
+               return err;
+       if (len == 0)
                return -ERANGE;
 
        priv->len = len;
index c6d5358482d12ce81b8f4782e72ba2dcdbfb1caa..8f0aaaea1376eb94e77d2bd21f00b54e6b0c3e6b 100644 (file)
@@ -28,22 +28,20 @@ static void nft_range_eval(const struct nft_expr *expr,
                         const struct nft_pktinfo *pkt)
 {
        const struct nft_range_expr *priv = nft_expr_priv(expr);
-       bool mismatch;
        int d1, d2;
 
        d1 = memcmp(&regs->data[priv->sreg], &priv->data_from, priv->len);
        d2 = memcmp(&regs->data[priv->sreg], &priv->data_to, priv->len);
        switch (priv->op) {
        case NFT_RANGE_EQ:
-               mismatch = (d1 < 0 || d2 > 0);
+               if (d1 < 0 || d2 > 0)
+                       regs->verdict.code = NFT_BREAK;
                break;
        case NFT_RANGE_NEQ:
-               mismatch = (d1 >= 0 && d2 <= 0);
+               if (d1 >= 0 && d2 <= 0)
+                       regs->verdict.code = NFT_BREAK;
                break;
        }
-
-       if (mismatch)
-               regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = {
@@ -59,6 +57,13 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr
        struct nft_range_expr *priv = nft_expr_priv(expr);
        struct nft_data_desc desc_from, desc_to;
        int err;
+       u32 op;
+
+       if (!tb[NFTA_RANGE_SREG]      ||
+           !tb[NFTA_RANGE_OP]        ||
+           !tb[NFTA_RANGE_FROM_DATA] ||
+           !tb[NFTA_RANGE_TO_DATA])
+               return -EINVAL;
 
        err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from),
                            &desc_from, tb[NFTA_RANGE_FROM_DATA]);
@@ -80,7 +85,20 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr
        if (err < 0)
                goto err2;
 
-       priv->op  = ntohl(nla_get_be32(tb[NFTA_RANGE_OP]));
+       err = nft_parse_u32_check(tb[NFTA_RANGE_OP], U8_MAX, &op);
+       if (err < 0)
+               goto err2;
+
+       switch (op) {
+       case NFT_RANGE_EQ:
+       case NFT_RANGE_NEQ:
+               break;
+       default:
+               err = -EINVAL;
+               goto err2;
+       }
+
+       priv->op  = op;
        priv->len = desc_from.len;
        return 0;
 err2:
index 3794cb2fc78876ce02eb35992cb0113d498367ba..a3dface3e6e6895e3d778c9378d4579b5723811d 100644 (file)
@@ -98,7 +98,7 @@ static bool nft_hash_update(struct nft_set *set, const u32 *key,
                            const struct nft_set_ext **ext)
 {
        struct nft_hash *priv = nft_set_priv(set);
-       struct nft_hash_elem *he;
+       struct nft_hash_elem *he, *prev;
        struct nft_hash_cmp_arg arg = {
                .genmask = NFT_GENMASK_ANY,
                .set     = set,
@@ -112,15 +112,24 @@ static bool nft_hash_update(struct nft_set *set, const u32 *key,
        he = new(set, expr, regs);
        if (he == NULL)
                goto err1;
-       if (rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
-                                        nft_hash_params))
+
+       prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
+                                               nft_hash_params);
+       if (IS_ERR(prev))
                goto err2;
+
+       /* Another cpu may race to insert the element with the same key */
+       if (prev) {
+               nft_set_elem_destroy(set, he, true);
+               he = prev;
+       }
+
 out:
        *ext = &he->ext;
        return true;
 
 err2:
-       nft_set_elem_destroy(set, he);
+       nft_set_elem_destroy(set, he, true);
 err1:
        return false;
 }
@@ -332,7 +341,7 @@ static int nft_hash_init(const struct nft_set *set,
 
 static void nft_hash_elem_destroy(void *ptr, void *arg)
 {
-       nft_set_elem_destroy((const struct nft_set *)arg, ptr);
+       nft_set_elem_destroy((const struct nft_set *)arg, ptr, true);
 }
 
 static void nft_hash_destroy(const struct nft_set *set)
index 38b5bda242f86fe4ca0e09d7f365892917d32c9f..36493a7cae8827fa41036f381d65d28d59b139b2 100644 (file)
@@ -266,7 +266,7 @@ static void nft_rbtree_destroy(const struct nft_set *set)
        while ((node = priv->root.rb_node) != NULL) {
                rb_erase(node, &priv->root);
                rbe = rb_entry(node, struct nft_rbtree_elem, node);
-               nft_set_elem_destroy(set, rbe);
+               nft_set_elem_destroy(set, rbe, true);
        }
 }
 
index e0aa7c1d0224154db4ef09c752b88ca5e52bc404..fc4977456c30e098197b4f987b758072c9cf60d9 100644 (file)
@@ -1513,7 +1513,7 @@ xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn)
        if (!num_hooks)
                return ERR_PTR(-EINVAL);
 
-       ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
+       ops = kcalloc(num_hooks, sizeof(*ops), GFP_KERNEL);
        if (ops == NULL)
                return ERR_PTR(-ENOMEM);
 
index 018eed7e1ff1e6f6c60dbe43a504e24c3860cf4d..8668a5c18dc3fd7595c0c752e9f01ff0d085be66 100644 (file)
@@ -32,6 +32,7 @@ nflog_tg(struct sk_buff *skb, const struct xt_action_param *par)
        li.u.ulog.copy_len   = info->len;
        li.u.ulog.group      = info->group;
        li.u.ulog.qthreshold = info->threshold;
+       li.u.ulog.flags      = 0;
 
        if (info->flags & XT_NFLOG_F_COPY_LEN)
                li.u.ulog.flags |= NF_LOG_F_COPY_LEN;
index 69f78e96fdb44a5c293a92e53a98559b1ddf2209..b83e158e116afc35f3a9ab7b739409b523cebb86 100644 (file)
@@ -44,7 +44,7 @@ connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
        u_int32_t newmark;
 
        ct = nf_ct_get(skb, &ctinfo);
-       if (ct == NULL)
+       if (ct == NULL || nf_ct_is_untracked(ct))
                return XT_CONTINUE;
 
        switch (info->mode) {
@@ -97,7 +97,7 @@ connmark_mt(const struct sk_buff *skb, struct xt_action_param *par)
        const struct nf_conn *ct;
 
        ct = nf_ct_get(skb, &ctinfo);
-       if (ct == NULL)
+       if (ct == NULL || nf_ct_is_untracked(ct))
                return false;
 
        return ((ct->mark & info->mask) == info->mark) ^ info->invert;
index 2fab0c65aa94b66615d7ba86b67d24e2cb15e89f..b89b688e9d01a2d14071563bb3e823b62dceeb17 100644 (file)
@@ -431,7 +431,7 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
    CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
 */
 #define MAX_CPJ_v1 (0xFFFFFFFF / (HZ*60*60*24))
-#define MAX_CPJ (0xFFFFFFFFFFFFFFFF / (HZ*60*60*24))
+#define MAX_CPJ (0xFFFFFFFFFFFFFFFFULL / (HZ*60*60*24))
 
 /* Repeated shift and or gives us all 1s, final shift and add 1 gives
  * us the power of 2 below the theoretical max, so GCC simply does a
@@ -473,7 +473,7 @@ static u64 user2credits(u64 user, int revision)
                return div64_u64(user * HZ * CREDITS_PER_JIFFY_v1,
                                 XT_HASHLIMIT_SCALE);
        } else {
-               if (user > 0xFFFFFFFFFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
+               if (user > 0xFFFFFFFFFFFFFFFFULL / (HZ*CREDITS_PER_JIFFY))
                        return div64_u64(user, XT_HASHLIMIT_SCALE_v2)
                                * HZ * CREDITS_PER_JIFFY;
 
index 89d53104c6b365b12c76ff684064bc5d032656c3..000e70377f85dd90fa61203ac4f18abfc62e57ec 100644 (file)
@@ -26,6 +26,8 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Fan Du <fan.du@windriver.com>");
 MODULE_DESCRIPTION("Xtables: IPv4/6 IPsec-IPComp SPI match");
+MODULE_ALIAS("ipt_ipcomp");
+MODULE_ALIAS("ip6t_ipcomp");
 
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline bool
index 62bea4591054820eb516ef016214ee23fe89b6e9..246f29d365c09a7761b8ae0f0a2acd6de8a6f653 100644 (file)
@@ -329,7 +329,6 @@ static void netlink_sock_destruct(struct sock *sk)
        if (nlk->cb_running) {
                if (nlk->cb.done)
                        nlk->cb.done(&nlk->cb);
-
                module_put(nlk->cb.module);
                kfree_skb(nlk->cb.skb);
        }
@@ -346,6 +345,14 @@ static void netlink_sock_destruct(struct sock *sk)
        WARN_ON(nlk_sk(sk)->groups);
 }
 
+static void netlink_sock_destruct_work(struct work_struct *work)
+{
+       struct netlink_sock *nlk = container_of(work, struct netlink_sock,
+                                               work);
+
+       sk_free(&nlk->sk);
+}
+
 /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on
  * SMP. Look, when several writers sleep and reader wakes them up, all but one
  * immediately hit write lock and grab all the cpus. Exclusive sleep solves
@@ -648,8 +655,18 @@ out_module:
 static void deferred_put_nlk_sk(struct rcu_head *head)
 {
        struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
+       struct sock *sk = &nlk->sk;
+
+       if (!atomic_dec_and_test(&sk->sk_refcnt))
+               return;
+
+       if (nlk->cb_running && nlk->cb.done) {
+               INIT_WORK(&nlk->work, netlink_sock_destruct_work);
+               schedule_work(&nlk->work);
+               return;
+       }
 
-       sock_put(&nlk->sk);
+       sk_free(sk);
 }
 
 static int netlink_release(struct socket *sock)
index 3cfd6cc60504385b98009f52748fc088c62a3b96..4fdb3831897775547f77c069a8018c0d2a253c8c 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/rhashtable.h>
 #include <linux/atomic.h>
+#include <linux/workqueue.h>
 #include <net/sock.h>
 
 #define NLGRPSZ(x)     (ALIGN(x, sizeof(unsigned long) * 8) / 8)
@@ -33,6 +34,7 @@ struct netlink_sock {
 
        struct rhash_head       node;
        struct rcu_head         rcu;
+       struct work_struct      work;
 };
 
 static inline struct netlink_sock *nlk_sk(struct sock *sk)
index b2f0e986a6f49e79d58e9706b7c822a1f11073bb..a5546249fb1022b52144a40717b8a4268755b972 100644 (file)
@@ -178,11 +178,8 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                }
                cb->args[1] = i;
        } else {
-               if (req->sdiag_protocol >= MAX_LINKS) {
-                       read_unlock(&nl_table_lock);
-                       rcu_read_unlock();
+               if (req->sdiag_protocol >= MAX_LINKS)
                        return -ENOENT;
-               }
 
                err = __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
        }
index 23cc12639ba769ac67714f5e5f5f9549a4417c38..49c28e8ef01b986c068ecc8e86d4d8546088c8f7 100644 (file)
@@ -404,7 +404,7 @@ int __genl_register_family(struct genl_family *family)
 
        err = genl_validate_assign_mc_groups(family);
        if (err)
-               goto errout_locked;
+               goto errout_free;
 
        list_add_tail(&family->family_list, genl_family_chain(family->id));
        genl_unlock_all();
@@ -417,6 +417,8 @@ int __genl_register_family(struct genl_family *family)
 
        return 0;
 
+errout_free:
+       kfree(family->attrbuf);
 errout_locked:
        genl_unlock_all();
 errout:
index 31045ef44a82b925e53ce34da2aca74448dd9c8d..fecefa2dc94e129935bcf9b5d1ff117e58566b9f 100644 (file)
@@ -370,8 +370,11 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
                skb_orphan(skb);
                memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
                err = nf_ct_frag6_gather(net, skb, user);
-               if (err)
+               if (err) {
+                       if (err != -EINPROGRESS)
+                               kfree_skb(skb);
                        return err;
+               }
 
                key->ip.proto = ipv6_hdr(skb)->nexthdr;
                ovs_cb.mru = IP6CB(skb)->frag_max_size;
index 11db0d619c007270e7ac003e916a4a4097a79dc9..dd2332390c45bbff7c3fc5d259453f2e1ca352bf 100644 (file)
@@ -250,7 +250,7 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po);
 static int packet_direct_xmit(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
-       netdev_features_t features;
+       struct sk_buff *orig_skb = skb;
        struct netdev_queue *txq;
        int ret = NETDEV_TX_BUSY;
 
@@ -258,9 +258,8 @@ static int packet_direct_xmit(struct sk_buff *skb)
                     !netif_carrier_ok(dev)))
                goto drop;
 
-       features = netif_skb_features(skb);
-       if (skb_needs_linearize(skb, features) &&
-           __skb_linearize(skb))
+       skb = validate_xmit_skb_list(skb, dev);
+       if (skb != orig_skb)
                goto drop;
 
        txq = skb_get_tx_queue(dev, skb);
@@ -280,7 +279,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
        return ret;
 drop:
        atomic_long_inc(&dev->tx_dropped);
-       kfree_skb(skb);
+       kfree_skb_list(skb);
        return NET_XMIT_DROP;
 }
 
@@ -3649,19 +3648,25 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 
                if (optlen != sizeof(val))
                        return -EINVAL;
-               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)
-                       return -EBUSY;
                if (copy_from_user(&val, optval, sizeof(val)))
                        return -EFAULT;
                switch (val) {
                case TPACKET_V1:
                case TPACKET_V2:
                case TPACKET_V3:
-                       po->tp_version = val;
-                       return 0;
+                       break;
                default:
                        return -EINVAL;
                }
+               lock_sock(sk);
+               if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {
+                       ret = -EBUSY;
+               } else {
+                       po->tp_version = val;
+                       ret = 0;
+               }
+               release_sock(sk);
+               return ret;
        }
        case PACKET_RESERVE:
        {
@@ -4165,6 +4170,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
        /* Added to avoid minimal code churn */
        struct tpacket_req *req = &req_u->req;
 
+       lock_sock(sk);
        /* Opening a Tx-ring is NOT supported in TPACKET_V3 */
        if (!closing && tx_ring && (po->tp_version > TPACKET_V2)) {
                net_warn_ratelimited("Tx-ring is not supported.\n");
@@ -4246,7 +4252,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                        goto out;
        }
 
-       lock_sock(sk);
 
        /* Detach socket from network */
        spin_lock(&po->bind_lock);
@@ -4295,11 +4300,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                if (!tx_ring)
                        prb_shutdown_retire_blk_timer(po, rb_queue);
        }
-       release_sock(sk);
 
        if (pg_vec)
                free_pg_vec(pg_vec, order, req->tp_block_nr);
 out:
+       release_sock(sk);
        return err;
 }
 
index 0e72bec1529f52116a1aa8a2a4512d903ce03a4b..56c7d27eefee759be0c4dab0f939c84df9c49560 100644 (file)
@@ -13,5 +13,5 @@ obj-$(CONFIG_RDS_TCP) += rds_tcp.o
 rds_tcp-y :=           tcp.o tcp_connect.o tcp_listen.o tcp_recv.o \
                        tcp_send.o tcp_stats.o
 
-ccflags-$(CONFIG_RDS_DEBUG)    :=      -DDEBUG
+ccflags-$(CONFIG_RDS_DEBUG)    :=      -DRDS_DEBUG
 
index fd0bccb2f9f9d895ccc997fc0d21b6d9549e6c2b..67ba67c058b1b6b8e02631d664c41cac4deaadcc 100644 (file)
@@ -33,7 +33,7 @@
 #define KERNEL_HAS_ATOMIC64
 #endif
 
-#ifdef DEBUG
+#ifdef RDS_DEBUG
 #define rdsdebug(fmt, args...) pr_debug("%s(): " fmt, __func__ , ##args)
 #else
 /* sigh, pr_debug() causes unused variable warnings */
index fcddacc92e018bee041f250cde5e48ba8ea70c6a..20e2923dc827fdc447082159bffe34d39caeca51 100644 (file)
@@ -659,6 +659,8 @@ out_recv:
 out_pernet:
        unregister_pernet_subsys(&rds_tcp_net_ops);
 out_slab:
+       if (unregister_netdevice_notifier(&rds_tcp_dev_notifier))
+               pr_warn("could not unregister rds_tcp_dev_notifier\n");
        kmem_cache_destroy(rds_tcp_conn_slab);
 out:
        return ret;
index 4353a29f3b5717d7ff67ae954e8cc1551b614160..1ed18d8c9c9fa31ac46028089184519624625a51 100644 (file)
@@ -276,7 +276,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
                goto error;
 
        trace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage),
-                        here, ERR_PTR(ret));
+                        here, NULL);
 
        spin_lock_bh(&call->conn->params.peer->lock);
        hlist_add_head(&call->error_link,
index 941b724d523bf282e5f8e6901a882c0d12effa0b..862eea6b266c95f7aaaba96d2a07b8f875f37167 100644 (file)
@@ -193,8 +193,8 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
                fl6->fl6_dport = htons(7001);
                fl6->fl6_sport = htons(7000);
                dst = ip6_route_output(&init_net, NULL, fl6);
-               if (IS_ERR(dst)) {
-                       _leave(" [route err %ld]", PTR_ERR(dst));
+               if (dst->error) {
+                       _leave(" [route err %d]", dst->error);
                        return;
                }
                break;
index a512b18c0088506bc577d8b3a1113871206c6d47..f893d180da1caa3b6dd1cc8773920beb1885f9b0 100644 (file)
@@ -1028,8 +1028,7 @@ static struct nlattr *find_dump_kind(const struct nlmsghdr *n)
 
        if (tb[1] == NULL)
                return NULL;
-       if (nla_parse(tb2, TCA_ACT_MAX, nla_data(tb[1]),
-                     nla_len(tb[1]), NULL) < 0)
+       if (nla_parse_nested(tb2, TCA_ACT_MAX, tb[1], NULL) < 0)
                return NULL;
        kind = tb2[TCA_ACT_KIND];
 
index 667dc382df82bf1b7f884b7d60b0907826cc21a3..6b07fba5770b2fd0997eef25be5ea2e2803b54ca 100644 (file)
@@ -207,8 +207,11 @@ out:
 static void tcf_stats_update(struct tc_action *a, u64 bytes, u32 packets,
                             u64 lastuse)
 {
-       tcf_lastuse_update(&a->tcfa_tm);
+       struct tcf_mirred *m = to_mirred(a);
+       struct tcf_t *tm = &m->tcf_tm;
+
        _bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), bytes, packets);
+       tm->lastuse = lastuse;
 }
 
 static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind,
index b54d56d4959b6381d35799ba84f64ea634384cce..cf9b2fe8eac6032f46a570c1482de601b41ac74f 100644 (file)
@@ -108,6 +108,17 @@ static void tcf_pedit_cleanup(struct tc_action *a, int bind)
        kfree(keys);
 }
 
+static bool offset_valid(struct sk_buff *skb, int offset)
+{
+       if (offset > 0 && offset > skb->len)
+               return false;
+
+       if  (offset < 0 && -offset > skb_headroom(skb))
+               return false;
+
+       return true;
+}
+
 static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a,
                     struct tcf_result *res)
 {
@@ -134,6 +145,11 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a,
                        if (tkey->offmask) {
                                char *d, _d;
 
+                               if (!offset_valid(skb, off + tkey->at)) {
+                                       pr_info("tc filter pedit 'at' offset %d out of bounds\n",
+                                               off + tkey->at);
+                                       goto bad;
+                               }
                                d = skb_header_pointer(skb, off + tkey->at, 1,
                                                       &_d);
                                if (!d)
@@ -146,10 +162,10 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a,
                                        " offset must be on 32 bit boundaries\n");
                                goto bad;
                        }
-                       if (offset > 0 && offset > skb->len) {
-                               pr_info("tc filter pedit"
-                                       " offset %d can't exceed pkt length %d\n",
-                                      offset, skb->len);
+
+                       if (!offset_valid(skb, off + offset)) {
+                               pr_info("tc filter pedit offset %d out of bounds\n",
+                                       offset);
                                goto bad;
                        }
 
index 2ee29a3375f6672812e45e12250ec90ac1ed892c..b05d4a2155b0b08ae7bb57c5bda2be2ee234679a 100644 (file)
@@ -345,7 +345,8 @@ replay:
                        if (err == 0) {
                                struct tcf_proto *next = rtnl_dereference(tp->next);
 
-                               tfilter_notify(net, skb, n, tp, fh,
+                               tfilter_notify(net, skb, n, tp,
+                                              t->tcm_handle,
                                               RTM_DELTFILTER, false);
                                if (tcf_destroy(tp, false))
                                        RCU_INIT_POINTER(*back, next);
@@ -429,7 +430,8 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
        if (!skb)
                return -ENOBUFS;
 
-       if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) {
+       if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq,
+                         n->nlmsg_flags, event) <= 0) {
                kfree_skb(skb);
                return -EINVAL;
        }
index eb219b78cd495fcee480f0c0fae355e8a3deea81..5877f6061b57589ce9ba9226281e85f47eafb523 100644 (file)
@@ -62,9 +62,6 @@ static unsigned long basic_get(struct tcf_proto *tp, u32 handle)
        struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f;
 
-       if (head == NULL)
-               return 0UL;
-
        list_for_each_entry(f, &head->flist, link) {
                if (f->handle == handle) {
                        l = (unsigned long) f;
@@ -109,7 +106,6 @@ static bool basic_destroy(struct tcf_proto *tp, bool force)
                tcf_unbind_filter(tp, &f->res);
                call_rcu(&f->rcu, basic_delete_filter);
        }
-       RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
        return true;
 }
index bb1d5a487081f21f80a3042cd424cf7caedf6b37..0a47ba5e610985d9c19db81a69de5b60db44348b 100644 (file)
@@ -292,7 +292,6 @@ static bool cls_bpf_destroy(struct tcf_proto *tp, bool force)
                call_rcu(&prog->rcu, __cls_bpf_delete_prog);
        }
 
-       RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
        return true;
 }
@@ -303,9 +302,6 @@ static unsigned long cls_bpf_get(struct tcf_proto *tp, u32 handle)
        struct cls_bpf_prog *prog;
        unsigned long ret = 0UL;
 
-       if (head == NULL)
-               return 0UL;
-
        list_for_each_entry(prog, &head->plist, link) {
                if (prog->handle == handle) {
                        ret = (unsigned long) prog;
index 85233c470035f7f618e7550a1789102e2208a757..c1f20077837f06bb1998f5621c797e575e10ca21 100644 (file)
@@ -137,11 +137,10 @@ static bool cls_cgroup_destroy(struct tcf_proto *tp, bool force)
 
        if (!force)
                return false;
-
-       if (head) {
-               RCU_INIT_POINTER(tp->root, NULL);
+       /* Head can still be NULL due to cls_cgroup_init(). */
+       if (head)
                call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
-       }
+
        return true;
 }
 
index e39672394c7b64dc28617878bc7b26ef1ef8abb9..6575aba87630a24052a6374ddfceef1ce597144d 100644 (file)
@@ -596,7 +596,6 @@ static bool flow_destroy(struct tcf_proto *tp, bool force)
                list_del_rcu(&f->list);
                call_rcu(&f->rcu, flow_destroy_filter);
        }
-       RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
        return true;
 }
index f6f40fba599bad3d1db4bb14fcc4f7d663d128bc..904442421db3afae405548a9f5c316ce65e22de3 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/rhashtable.h>
+#include <linux/workqueue.h>
 
 #include <linux/if_ether.h>
 #include <linux/in6.h>
@@ -64,7 +65,10 @@ struct cls_fl_head {
        bool mask_assigned;
        struct list_head filters;
        struct rhashtable_params ht_params;
-       struct rcu_head rcu;
+       union {
+               struct work_struct work;
+               struct rcu_head rcu;
+       };
 };
 
 struct cls_fl_filter {
@@ -269,6 +273,24 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
        dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
 }
 
+static void fl_destroy_sleepable(struct work_struct *work)
+{
+       struct cls_fl_head *head = container_of(work, struct cls_fl_head,
+                                               work);
+       if (head->mask_assigned)
+               rhashtable_destroy(&head->ht);
+       kfree(head);
+       module_put(THIS_MODULE);
+}
+
+static void fl_destroy_rcu(struct rcu_head *rcu)
+{
+       struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu);
+
+       INIT_WORK(&head->work, fl_destroy_sleepable);
+       schedule_work(&head->work);
+}
+
 static bool fl_destroy(struct tcf_proto *tp, bool force)
 {
        struct cls_fl_head *head = rtnl_dereference(tp->root);
@@ -282,10 +304,9 @@ static bool fl_destroy(struct tcf_proto *tp, bool force)
                list_del_rcu(&f->list);
                call_rcu(&f->rcu, fl_destroy_filter);
        }
-       RCU_INIT_POINTER(tp->root, NULL);
-       if (head->mask_assigned)
-               rhashtable_destroy(&head->ht);
-       kfree_rcu(head, rcu);
+
+       __module_get(THIS_MODULE);
+       call_rcu(&head->rcu, fl_destroy_rcu);
        return true;
 }
 
@@ -711,8 +732,9 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
                goto errout;
 
        if (fold) {
-               rhashtable_remove_fast(&head->ht, &fold->ht_node,
-                                      head->ht_params);
+               if (!tc_skip_sw(fold->flags))
+                       rhashtable_remove_fast(&head->ht, &fold->ht_node,
+                                              head->ht_params);
                fl_hw_destroy_filter(tp, (unsigned long)fold);
        }
 
@@ -739,8 +761,9 @@ static int fl_delete(struct tcf_proto *tp, unsigned long arg)
        struct cls_fl_head *head = rtnl_dereference(tp->root);
        struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
 
-       rhashtable_remove_fast(&head->ht, &f->ht_node,
-                              head->ht_params);
+       if (!tc_skip_sw(f->flags))
+               rhashtable_remove_fast(&head->ht, &f->ht_node,
+                                      head->ht_params);
        list_del_rcu(&f->list);
        fl_hw_destroy_filter(tp, (unsigned long)f);
        tcf_unbind_filter(tp, &f->res);
index 25927b6c4436775a0d80747f7171ddc3d6896dfd..f935429bd5ef1fcbe6a4272876b76e2ebb574c4b 100644 (file)
@@ -114,7 +114,6 @@ static bool mall_destroy(struct tcf_proto *tp, bool force)
 
                call_rcu(&f->rcu, mall_destroy_filter);
        }
-       RCU_INIT_POINTER(tp->root, NULL);
        kfree_rcu(head, rcu);
        return true;
 }
index 4f05a19fb07358d6a1763f279dec9ea5f32f32ad..322438fb3ffcb426194be6c1dd05893b27cdf51c 100644 (file)
@@ -152,7 +152,8 @@ static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                return -1;
        nhptr = ip_hdr(skb);
 #endif
-
+       if (unlikely(!head))
+               return -1;
 restart:
 
 #if RSVP_DST_LEN == 4
index 96144bdf30db37d1ebd7dbaa0314d273f0f6aef2..0751245a6aced60163601b94ab1386e0c5e30565 100644 (file)
@@ -543,7 +543,6 @@ static bool tcindex_destroy(struct tcf_proto *tp, bool force)
        walker.fn = tcindex_destroy_element;
        tcindex_walk(tp, &walker);
 
-       RCU_INIT_POINTER(tp->root, NULL);
        call_rcu(&p->rcu, __tcindex_destroy);
        return true;
 }
index a2ea1d1cc06a9705dab0ab74d6f0490f0d0604e1..a01a56ec8b8cd3709aaf0f2af81ead42b4faa05f 100644 (file)
@@ -181,9 +181,10 @@ int sctp_rcv(struct sk_buff *skb)
         * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB
         */
        if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) {
-               if (asoc) {
-                       sctp_association_put(asoc);
+               if (transport) {
+                       sctp_transport_put(transport);
                        asoc = NULL;
+                       transport = NULL;
                } else {
                        sctp_endpoint_put(ep);
                        ep = NULL;
@@ -269,8 +270,8 @@ int sctp_rcv(struct sk_buff *skb)
        bh_unlock_sock(sk);
 
        /* Release the asoc/ep ref we took in the lookup calls. */
-       if (asoc)
-               sctp_association_put(asoc);
+       if (transport)
+               sctp_transport_put(transport);
        else
                sctp_endpoint_put(ep);
 
@@ -283,8 +284,8 @@ discard_it:
 
 discard_release:
        /* Release the asoc/ep ref we took in the lookup calls. */
-       if (asoc)
-               sctp_association_put(asoc);
+       if (transport)
+               sctp_transport_put(transport);
        else
                sctp_endpoint_put(ep);
 
@@ -300,6 +301,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
        struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
+       struct sctp_transport *t = chunk->transport;
        struct sctp_ep_common *rcvr = NULL;
        int backloged = 0;
 
@@ -351,7 +353,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 done:
        /* Release the refs we took in sctp_add_backlog */
        if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
-               sctp_association_put(sctp_assoc(rcvr));
+               sctp_transport_put(t);
        else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
                sctp_endpoint_put(sctp_ep(rcvr));
        else
@@ -363,6 +365,7 @@ done:
 static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
        struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
+       struct sctp_transport *t = chunk->transport;
        struct sctp_ep_common *rcvr = chunk->rcvr;
        int ret;
 
@@ -373,7 +376,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
                 * from us
                 */
                if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
-                       sctp_association_hold(sctp_assoc(rcvr));
+                       sctp_transport_hold(t);
                else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
                        sctp_endpoint_hold(sctp_ep(rcvr));
                else
@@ -537,15 +540,15 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
        return sk;
 
 out:
-       sctp_association_put(asoc);
+       sctp_transport_put(transport);
        return NULL;
 }
 
 /* Common cleanup code for icmp/icmpv6 error handler. */
-void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)
+void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
 {
        bh_unlock_sock(sk);
-       sctp_association_put(asoc);
+       sctp_transport_put(t);
 }
 
 /*
@@ -641,7 +644,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
        }
 
 out_unlock:
-       sctp_err_finish(sk, asoc);
+       sctp_err_finish(sk, transport);
 }
 
 /*
@@ -952,11 +955,8 @@ static struct sctp_association *__sctp_lookup_association(
                goto out;
 
        asoc = t->asoc;
-       sctp_association_hold(asoc);
        *pt = t;
 
-       sctp_transport_put(t);
-
 out:
        return asoc;
 }
@@ -986,7 +986,7 @@ int sctp_has_association(struct net *net,
        struct sctp_transport *transport;
 
        if ((asoc = sctp_lookup_association(net, laddr, paddr, &transport))) {
-               sctp_association_put(asoc);
+               sctp_transport_put(transport);
                return 1;
        }
 
@@ -1021,7 +1021,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net,
        struct sctphdr *sh = sctp_hdr(skb);
        union sctp_params params;
        sctp_init_chunk_t *init;
-       struct sctp_transport *transport;
        struct sctp_af *af;
 
        /*
@@ -1052,7 +1051,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct net *net,
 
                af->from_addr_param(paddr, params.addr, sh->source, 0);
 
-               asoc = __sctp_lookup_association(net, laddr, paddr, &transport);
+               asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
                if (asoc)
                        return asoc;
        }
index f473779e8b1c3f4d82f47fe5d2ccadc2d47af45f..176af3080a2b8f8ffc56b55f3ccb13a169e195fe 100644 (file)
@@ -198,7 +198,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        }
 
 out_unlock:
-       sctp_err_finish(sk, asoc);
+       sctp_err_finish(sk, transport);
 out:
        if (likely(idev != NULL))
                in6_dev_put(idev);
index 2a5c1896d18fa674f0e0e84ff6787d04914b2b73..6cb0df859195ecea93105e396e43f181e53f2e79 100644 (file)
@@ -418,6 +418,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
        __u8 has_data = 0;
        int gso = 0;
        int pktcount = 0;
+       int auth_len = 0;
        struct dst_entry *dst;
        unsigned char *auth = NULL;     /* pointer to auth in skb data */
 
@@ -510,7 +511,12 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
                        list_for_each_entry(chunk, &packet->chunk_list, list) {
                                int padded = SCTP_PAD4(chunk->skb->len);
 
-                               if (pkt_size + padded > tp->pathmtu)
+                               if (chunk == packet->auth)
+                                       auth_len = padded;
+                               else if (auth_len + padded + packet->overhead >
+                                        tp->pathmtu)
+                                       goto nomem;
+                               else if (pkt_size + padded > tp->pathmtu)
                                        break;
                                pkt_size += padded;
                        }
index 026e3bca4a94bd34b418d5e6947f7182c1512358..8ec20a64a3f8055a0c3576627c5ec5dad7e99ca8 100644 (file)
@@ -3422,6 +3422,12 @@ sctp_disposition_t sctp_sf_ootb(struct net *net,
                        return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
+               /* Report violation if chunk len overflows */
+               ch_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length));
+               if (ch_end > skb_tail_pointer(skb))
+                       return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
+                                                 commands);
+
                /* Now that we know we at least have a chunk header,
                 * do things that are type appropriate.
                 */
@@ -3453,12 +3459,6 @@ sctp_disposition_t sctp_sf_ootb(struct net *net,
                        }
                }
 
-               /* Report violation if chunk len overflows */
-               ch_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length));
-               if (ch_end > skb_tail_pointer(skb))
-                       return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
-                                                 commands);
-
                ch = (sctp_chunkhdr_t *) ch_end;
        } while (ch_end < skb_tail_pointer(skb));
 
index fb02c70333078743e832a7a991f7a44770d19bcc..f23ad913dc7a070407813b44acb500a5f7c148e9 100644 (file)
@@ -1214,9 +1214,12 @@ static int __sctp_connect(struct sock *sk,
 
        timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
 
-       err = sctp_wait_for_connect(asoc, &timeo);
-       if ((err == 0 || err == -EINPROGRESS) && assoc_id)
+       if (assoc_id)
                *assoc_id = asoc->assoc_id;
+       err = sctp_wait_for_connect(asoc, &timeo);
+       /* Note: the asoc may be freed after the return of
+        * sctp_wait_for_connect.
+        */
 
        /* Don't free association on exit. */
        asoc = NULL;
@@ -4282,19 +4285,18 @@ static void sctp_shutdown(struct sock *sk, int how)
 {
        struct net *net = sock_net(sk);
        struct sctp_endpoint *ep;
-       struct sctp_association *asoc;
 
        if (!sctp_style(sk, TCP))
                return;
 
-       if (how & SEND_SHUTDOWN) {
+       ep = sctp_sk(sk)->ep;
+       if (how & SEND_SHUTDOWN && !list_empty(&ep->asocs)) {
+               struct sctp_association *asoc;
+
                sk->sk_state = SCTP_SS_CLOSING;
-               ep = sctp_sk(sk)->ep;
-               if (!list_empty(&ep->asocs)) {
-                       asoc = list_entry(ep->asocs.next,
-                                         struct sctp_association, asocs);
-                       sctp_primitive_SHUTDOWN(net, asoc, NULL);
-               }
+               asoc = list_entry(ep->asocs.next,
+                                 struct sctp_association, asocs);
+               sctp_primitive_SHUTDOWN(net, asoc, NULL);
        }
 }
 
@@ -4480,12 +4482,9 @@ int sctp_transport_lookup_process(int (*cb)(struct sctp_transport *, void *),
        if (!transport || !sctp_transport_hold(transport))
                goto out;
 
-       sctp_association_hold(transport->asoc);
-       sctp_transport_put(transport);
-
        rcu_read_unlock();
        err = cb(transport, p);
-       sctp_association_put(transport->asoc);
+       sctp_transport_put(transport);
 
 out:
        return err;
@@ -4687,7 +4686,7 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
 static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
                                  int __user *optlen)
 {
-       if (len <= 0)
+       if (len == 0)
                return -EINVAL;
        if (len > sizeof(struct sctp_event_subscribe))
                len = sizeof(struct sctp_event_subscribe);
@@ -6430,6 +6429,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
        if (get_user(len, optlen))
                return -EFAULT;
 
+       if (len < 0)
+               return -EINVAL;
+
        lock_sock(sk);
 
        switch (optname) {
index 5a9bf5ee2464da20fbb42ea6699b29318553e210..73dc69f9681e7b63d3916d561812cf8419764f31 100644 (file)
@@ -341,8 +341,23 @@ static const struct xattr_handler sockfs_xattr_handler = {
        .get = sockfs_xattr_get,
 };
 
+static int sockfs_security_xattr_set(const struct xattr_handler *handler,
+                                    struct dentry *dentry, struct inode *inode,
+                                    const char *suffix, const void *value,
+                                    size_t size, int flags)
+{
+       /* Handled by LSM. */
+       return -EAGAIN;
+}
+
+static const struct xattr_handler sockfs_security_xattr_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .set = sockfs_security_xattr_set,
+};
+
 static const struct xattr_handler *sockfs_xattr_handlers[] = {
        &sockfs_xattr_handler,
+       &sockfs_security_xattr_handler,
        NULL
 };
 
@@ -2038,6 +2053,8 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                if (err)
                        break;
                ++datagrams;
+               if (msg_data_left(&msg_sys))
+                       break;
                cond_resched();
        }
 
index d8bd97a5a7c9d807fd478befe92bea4ea7a40407..3dfd769dc5b51a724f20273eb0c52e5d6e25e9f1 100644 (file)
@@ -1616,7 +1616,7 @@ gss_validate(struct rpc_task *task, __be32 *p)
 {
        struct rpc_cred *cred = task->tk_rqstp->rq_cred;
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
-       __be32          seq;
+       __be32          *seq = NULL;
        struct kvec     iov;
        struct xdr_buf  verf_buf;
        struct xdr_netobj mic;
@@ -1631,9 +1631,12 @@ gss_validate(struct rpc_task *task, __be32 *p)
                goto out_bad;
        if (flav != RPC_AUTH_GSS)
                goto out_bad;
-       seq = htonl(task->tk_rqstp->rq_seqno);
-       iov.iov_base = &seq;
-       iov.iov_len = sizeof(seq);
+       seq = kmalloc(4, GFP_NOFS);
+       if (!seq)
+               goto out_bad;
+       *seq = htonl(task->tk_rqstp->rq_seqno);
+       iov.iov_base = seq;
+       iov.iov_len = 4;
        xdr_buf_from_iov(&iov, &verf_buf);
        mic.data = (u8 *)p;
        mic.len = len;
@@ -1653,11 +1656,13 @@ gss_validate(struct rpc_task *task, __be32 *p)
        gss_put_ctx(ctx);
        dprintk("RPC: %5u %s: gss_verify_mic succeeded.\n",
                        task->tk_pid, __func__);
+       kfree(seq);
        return p + XDR_QUADLEN(len);
 out_bad:
        gss_put_ctx(ctx);
        dprintk("RPC: %5u %s failed ret %ld.\n", task->tk_pid, __func__,
                PTR_ERR(ret));
+       kfree(seq);
        return ret;
 }
 
index 244245bcbbd25554938ab099137799d47ef6791b..90115ceefd490f39456edacfca6e711c47929ec0 100644 (file)
@@ -166,8 +166,8 @@ make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen,
                       unsigned int usage, struct xdr_netobj *cksumout)
 {
        struct scatterlist              sg[1];
-       int err;
-       u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+       int err = -1;
+       u8 *checksumdata;
        u8 rc4salt[4];
        struct crypto_ahash *md5;
        struct crypto_ahash *hmac_md5;
@@ -187,23 +187,22 @@ make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen,
                return GSS_S_FAILURE;
        }
 
+       checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS);
+       if (!checksumdata)
+               return GSS_S_FAILURE;
+
        md5 = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(md5))
-               return GSS_S_FAILURE;
+               goto out_free_cksum;
 
        hmac_md5 = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0,
                                      CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hmac_md5)) {
-               crypto_free_ahash(md5);
-               return GSS_S_FAILURE;
-       }
+       if (IS_ERR(hmac_md5))
+               goto out_free_md5;
 
        req = ahash_request_alloc(md5, GFP_KERNEL);
-       if (!req) {
-               crypto_free_ahash(hmac_md5);
-               crypto_free_ahash(md5);
-               return GSS_S_FAILURE;
-       }
+       if (!req)
+               goto out_free_hmac_md5;
 
        ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
 
@@ -232,11 +231,8 @@ make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen,
 
        ahash_request_free(req);
        req = ahash_request_alloc(hmac_md5, GFP_KERNEL);
-       if (!req) {
-               crypto_free_ahash(hmac_md5);
-               crypto_free_ahash(md5);
-               return GSS_S_FAILURE;
-       }
+       if (!req)
+               goto out_free_hmac_md5;
 
        ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
 
@@ -258,8 +254,12 @@ make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen,
        cksumout->len = kctx->gk5e->cksumlength;
 out:
        ahash_request_free(req);
-       crypto_free_ahash(md5);
+out_free_hmac_md5:
        crypto_free_ahash(hmac_md5);
+out_free_md5:
+       crypto_free_ahash(md5);
+out_free_cksum:
+       kfree(checksumdata);
        return err ? GSS_S_FAILURE : 0;
 }
 
@@ -276,8 +276,8 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
        struct crypto_ahash *tfm;
        struct ahash_request *req;
        struct scatterlist              sg[1];
-       int err;
-       u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+       int err = -1;
+       u8 *checksumdata;
        unsigned int checksumlen;
 
        if (kctx->gk5e->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR)
@@ -291,15 +291,17 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
                return GSS_S_FAILURE;
        }
 
+       checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS);
+       if (checksumdata == NULL)
+               return GSS_S_FAILURE;
+
        tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(tfm))
-               return GSS_S_FAILURE;
+               goto out_free_cksum;
 
        req = ahash_request_alloc(tfm, GFP_KERNEL);
-       if (!req) {
-               crypto_free_ahash(tfm);
-               return GSS_S_FAILURE;
-       }
+       if (!req)
+               goto out_free_ahash;
 
        ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
 
@@ -349,7 +351,10 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
        cksumout->len = kctx->gk5e->cksumlength;
 out:
        ahash_request_free(req);
+out_free_ahash:
        crypto_free_ahash(tfm);
+out_free_cksum:
+       kfree(checksumdata);
        return err ? GSS_S_FAILURE : 0;
 }
 
@@ -368,8 +373,8 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
        struct crypto_ahash *tfm;
        struct ahash_request *req;
        struct scatterlist sg[1];
-       int err;
-       u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+       int err = -1;
+       u8 *checksumdata;
        unsigned int checksumlen;
 
        if (kctx->gk5e->keyed_cksum == 0) {
@@ -383,16 +388,18 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
                return GSS_S_FAILURE;
        }
 
+       checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS);
+       if (!checksumdata)
+               return GSS_S_FAILURE;
+
        tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(tfm))
-               return GSS_S_FAILURE;
+               goto out_free_cksum;
        checksumlen = crypto_ahash_digestsize(tfm);
 
        req = ahash_request_alloc(tfm, GFP_KERNEL);
-       if (!req) {
-               crypto_free_ahash(tfm);
-               return GSS_S_FAILURE;
-       }
+       if (!req)
+               goto out_free_ahash;
 
        ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
 
@@ -433,7 +440,10 @@ make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
        }
 out:
        ahash_request_free(req);
+out_free_ahash:
        crypto_free_ahash(tfm);
+out_free_cksum:
+       kfree(checksumdata);
        return err ? GSS_S_FAILURE : 0;
 }
 
@@ -666,14 +676,17 @@ gss_krb5_cts_crypt(struct crypto_skcipher *cipher, struct xdr_buf *buf,
        u32 ret;
        struct scatterlist sg[1];
        SKCIPHER_REQUEST_ON_STACK(req, cipher);
-       u8 data[GSS_KRB5_MAX_BLOCKSIZE * 2];
+       u8 *data;
        struct page **save_pages;
        u32 len = buf->len - offset;
 
-       if (len > ARRAY_SIZE(data)) {
+       if (len > GSS_KRB5_MAX_BLOCKSIZE * 2) {
                WARN_ON(0);
                return -ENOMEM;
        }
+       data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_NOFS);
+       if (!data)
+               return -ENOMEM;
 
        /*
         * For encryption, we want to read from the cleartext
@@ -708,6 +721,7 @@ gss_krb5_cts_crypt(struct crypto_skcipher *cipher, struct xdr_buf *buf,
        ret = write_bytes_to_xdr_buf(buf, offset, data, len);
 
 out:
+       kfree(data);
        return ret;
 }
 
index d67f7e1bc82ddc55f6f9927343387f20fa81fa32..45662d7f0943c671297955e0c44e7632460c2c68 100644 (file)
@@ -718,30 +718,37 @@ gss_write_null_verf(struct svc_rqst *rqstp)
 static int
 gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
 {
-       __be32                  xdr_seq;
+       __be32                  *xdr_seq;
        u32                     maj_stat;
        struct xdr_buf          verf_data;
        struct xdr_netobj       mic;
        __be32                  *p;
        struct kvec             iov;
+       int err = -1;
 
        svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS);
-       xdr_seq = htonl(seq);
+       xdr_seq = kmalloc(4, GFP_KERNEL);
+       if (!xdr_seq)
+               return -1;
+       *xdr_seq = htonl(seq);
 
-       iov.iov_base = &xdr_seq;
-       iov.iov_len = sizeof(xdr_seq);
+       iov.iov_base = xdr_seq;
+       iov.iov_len = 4;
        xdr_buf_from_iov(&iov, &verf_data);
        p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
        mic.data = (u8 *)(p + 1);
        maj_stat = gss_get_mic(ctx_id, &verf_data, &mic);
        if (maj_stat != GSS_S_COMPLETE)
-               return -1;
+               goto out;
        *p++ = htonl(mic.len);
        memset((u8 *)p + mic.len, 0, round_up_to_quad(mic.len) - mic.len);
        p += XDR_QUADLEN(mic.len);
        if (!xdr_ressize_check(rqstp, p))
-               return -1;
-       return 0;
+               goto out;
+       err = 0;
+out:
+       kfree(xdr_seq);
+       return err;
 }
 
 struct gss_domain {
index 34dd7b26ee5f16589a46f8c7faa158570ccec9ad..62a482790937b54a5d486bc932289b0fb14da248 100644 (file)
@@ -2753,14 +2753,18 @@ EXPORT_SYMBOL_GPL(rpc_cap_max_reconnect_timeout);
 
 void rpc_clnt_xprt_switch_put(struct rpc_clnt *clnt)
 {
+       rcu_read_lock();
        xprt_switch_put(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_put);
 
 void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
 {
+       rcu_read_lock();
        rpc_xprt_switch_add_xprt(rcu_dereference(clnt->cl_xpi.xpi_xpswitch),
                                 xprt);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_add_xprt);
 
@@ -2770,9 +2774,8 @@ bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
        struct rpc_xprt_switch *xps;
        bool ret;
 
-       xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
-
        rcu_read_lock();
+       xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
        ret = rpc_xprt_switch_has_addr(xps, sap);
        rcu_read_unlock();
        return ret;
index c3f652395a80b8ded540bc60fe235ce504e239f7..3bc1d61694cbbbf7a094a1849b747b65760550b2 100644 (file)
@@ -1002,14 +1002,8 @@ static void svc_age_temp_xprts(unsigned long closure)
 void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
 {
        struct svc_xprt *xprt;
-       struct svc_sock *svsk;
-       struct socket *sock;
        struct list_head *le, *next;
        LIST_HEAD(to_be_closed);
-       struct linger no_linger = {
-               .l_onoff = 1,
-               .l_linger = 0,
-       };
 
        spin_lock_bh(&serv->sv_lock);
        list_for_each_safe(le, next, &serv->sv_tempsocks) {
@@ -1027,10 +1021,7 @@ void svc_age_temp_xprts_now(struct svc_serv *serv, struct sockaddr *server_addr)
                list_del_init(le);
                xprt = list_entry(le, struct svc_xprt, xpt_list);
                dprintk("svc_age_temp_xprts_now: closing %p\n", xprt);
-               svsk = container_of(xprt, struct svc_sock, sk_xprt);
-               sock = svsk->sk_sock;
-               kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
-                                 (char *)&no_linger, sizeof(no_linger));
+               xprt->xpt_ops->xpo_kill_temp_xprt(xprt);
                svc_close_xprt(xprt);
        }
 }
index 57625f64efd56edaa65fe0940aaa7979fe65ef87..a4bc98265d881b93036a77840f40882f2a2aaecb 100644 (file)
@@ -438,6 +438,21 @@ static int svc_tcp_has_wspace(struct svc_xprt *xprt)
        return !test_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
 }
 
+static void svc_tcp_kill_temp_xprt(struct svc_xprt *xprt)
+{
+       struct svc_sock *svsk;
+       struct socket *sock;
+       struct linger no_linger = {
+               .l_onoff = 1,
+               .l_linger = 0,
+       };
+
+       svsk = container_of(xprt, struct svc_sock, sk_xprt);
+       sock = svsk->sk_sock;
+       kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
+                         (char *)&no_linger, sizeof(no_linger));
+}
+
 /*
  * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo
  */
@@ -648,6 +663,10 @@ static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
        return NULL;
 }
 
+static void svc_udp_kill_temp_xprt(struct svc_xprt *xprt)
+{
+}
+
 static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
                                       struct net *net,
                                       struct sockaddr *sa, int salen,
@@ -667,6 +686,7 @@ static struct svc_xprt_ops svc_udp_ops = {
        .xpo_has_wspace = svc_udp_has_wspace,
        .xpo_accept = svc_udp_accept,
        .xpo_secure_port = svc_sock_secure_port,
+       .xpo_kill_temp_xprt = svc_udp_kill_temp_xprt,
 };
 
 static struct svc_xprt_class svc_udp_class = {
@@ -1242,6 +1262,7 @@ static struct svc_xprt_ops svc_tcp_ops = {
        .xpo_has_wspace = svc_tcp_has_wspace,
        .xpo_accept = svc_tcp_accept,
        .xpo_secure_port = svc_sock_secure_port,
+       .xpo_kill_temp_xprt = svc_tcp_kill_temp_xprt,
 };
 
 static struct svc_xprt_class svc_tcp_class = {
index 210949562786665ea1a2990e2e9e6f886e580af6..26b26beef2d4a6dd7ef9d31f09de7fe51504d841 100644 (file)
  * being done.
  *
  * When the underlying transport disconnects, MRs are left in one of
- * three states:
+ * four states:
  *
  * INVALID:    The MR was not in use before the QP entered ERROR state.
- *             (Or, the LOCAL_INV WR has not completed or flushed yet).
- *
- * STALE:      The MR was being registered or unregistered when the QP
- *             entered ERROR state, and the pending WR was flushed.
  *
  * VALID:      The MR was registered before the QP entered ERROR state.
  *
- * When frwr_op_map encounters STALE and VALID MRs, they are recovered
- * with ib_dereg_mr and then are re-initialized. Beause MR recovery
+ * FLUSHED_FR: The MR was being registered when the QP entered ERROR
+ *             state, and the pending WR was flushed.
+ *
+ * FLUSHED_LI: The MR was being invalidated when the QP entered ERROR
+ *             state, and the pending WR was flushed.
+ *
+ * When frwr_op_map encounters FLUSHED and VALID MRs, they are recovered
+ * with ib_dereg_mr and then are re-initialized. Because MR recovery
  * allocates fresh resources, it is deferred to a workqueue, and the
  * recovered MRs are placed back on the rb_mws list when recovery is
  * complete. frwr_op_map allocates another MR for the current RPC while
@@ -177,12 +179,15 @@ __frwr_reset_mr(struct rpcrdma_ia *ia, struct rpcrdma_mw *r)
 static void
 frwr_op_recover_mr(struct rpcrdma_mw *mw)
 {
+       enum rpcrdma_frmr_state state = mw->frmr.fr_state;
        struct rpcrdma_xprt *r_xprt = mw->mw_xprt;
        struct rpcrdma_ia *ia = &r_xprt->rx_ia;
        int rc;
 
        rc = __frwr_reset_mr(ia, mw);
-       ib_dma_unmap_sg(ia->ri_device, mw->mw_sg, mw->mw_nents, mw->mw_dir);
+       if (state != FRMR_FLUSHED_LI)
+               ib_dma_unmap_sg(ia->ri_device,
+                               mw->mw_sg, mw->mw_nents, mw->mw_dir);
        if (rc)
                goto out_release;
 
@@ -262,10 +267,8 @@ frwr_op_maxpages(struct rpcrdma_xprt *r_xprt)
 }
 
 static void
-__frwr_sendcompletion_flush(struct ib_wc *wc, struct rpcrdma_frmr *frmr,
-                           const char *wr)
+__frwr_sendcompletion_flush(struct ib_wc *wc, const char *wr)
 {
-       frmr->fr_state = FRMR_IS_STALE;
        if (wc->status != IB_WC_WR_FLUSH_ERR)
                pr_err("rpcrdma: %s: %s (%u/0x%x)\n",
                       wr, ib_wc_status_msg(wc->status),
@@ -288,7 +291,8 @@ frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc)
        if (wc->status != IB_WC_SUCCESS) {
                cqe = wc->wr_cqe;
                frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
-               __frwr_sendcompletion_flush(wc, frmr, "fastreg");
+               frmr->fr_state = FRMR_FLUSHED_FR;
+               __frwr_sendcompletion_flush(wc, "fastreg");
        }
 }
 
@@ -308,7 +312,8 @@ frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc)
        if (wc->status != IB_WC_SUCCESS) {
                cqe = wc->wr_cqe;
                frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
-               __frwr_sendcompletion_flush(wc, frmr, "localinv");
+               frmr->fr_state = FRMR_FLUSHED_LI;
+               __frwr_sendcompletion_flush(wc, "localinv");
        }
 }
 
@@ -328,8 +333,10 @@ frwr_wc_localinv_wake(struct ib_cq *cq, struct ib_wc *wc)
        /* WARNING: Only wr_cqe and status are reliable at this point */
        cqe = wc->wr_cqe;
        frmr = container_of(cqe, struct rpcrdma_frmr, fr_cqe);
-       if (wc->status != IB_WC_SUCCESS)
-               __frwr_sendcompletion_flush(wc, frmr, "localinv");
+       if (wc->status != IB_WC_SUCCESS) {
+               frmr->fr_state = FRMR_FLUSHED_LI;
+               __frwr_sendcompletion_flush(wc, "localinv");
+       }
        complete(&frmr->fr_linv_done);
 }
 
index 2d8545c3409596190d027e8ad73651903f25a6aa..20027f8de129e61faba9037d552eb826ecc34ae4 100644 (file)
@@ -177,18 +177,26 @@ xprt_rdma_bc_allocate(struct rpc_task *task)
                return -EINVAL;
        }
 
+       /* svc_rdma_sendto releases this page */
        page = alloc_page(RPCRDMA_DEF_GFP);
        if (!page)
                return -ENOMEM;
-
        rqst->rq_buffer = page_address(page);
+
+       rqst->rq_rbuffer = kmalloc(rqst->rq_rcvsize, RPCRDMA_DEF_GFP);
+       if (!rqst->rq_rbuffer) {
+               put_page(page);
+               return -ENOMEM;
+       }
        return 0;
 }
 
 static void
 xprt_rdma_bc_free(struct rpc_task *task)
 {
-       /* No-op: ctxt and page have already been freed. */
+       struct rpc_rqst *rqst = task->tk_rqstp;
+
+       kfree(rqst->rq_rbuffer);
 }
 
 static int
index 6864fb967038d3bc8c410502f11a56aa442c661e..1334de2715c28112bf4f4b77600e2e78218dc853 100644 (file)
@@ -67,6 +67,7 @@ static void svc_rdma_detach(struct svc_xprt *xprt);
 static void svc_rdma_free(struct svc_xprt *xprt);
 static int svc_rdma_has_wspace(struct svc_xprt *xprt);
 static int svc_rdma_secure_port(struct svc_rqst *);
+static void svc_rdma_kill_temp_xprt(struct svc_xprt *);
 
 static struct svc_xprt_ops svc_rdma_ops = {
        .xpo_create = svc_rdma_create,
@@ -79,6 +80,7 @@ static struct svc_xprt_ops svc_rdma_ops = {
        .xpo_has_wspace = svc_rdma_has_wspace,
        .xpo_accept = svc_rdma_accept,
        .xpo_secure_port = svc_rdma_secure_port,
+       .xpo_kill_temp_xprt = svc_rdma_kill_temp_xprt,
 };
 
 struct svc_xprt_class svc_rdma_class = {
@@ -1317,6 +1319,10 @@ static int svc_rdma_secure_port(struct svc_rqst *rqstp)
        return 1;
 }
 
+static void svc_rdma_kill_temp_xprt(struct svc_xprt *xprt)
+{
+}
+
 int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
 {
        struct ib_send_wr *bad_wr, *n_wr;
index 0d35b761c883d01a044ba5f9c635bb3a7edce741..6e1bba358203694e79cbc9074554b12053fa45c7 100644 (file)
@@ -216,7 +216,8 @@ struct rpcrdma_rep {
 enum rpcrdma_frmr_state {
        FRMR_IS_INVALID,        /* ready to be used */
        FRMR_IS_VALID,          /* in use */
-       FRMR_IS_STALE,          /* failed completion */
+       FRMR_FLUSHED_FR,        /* flushed FASTREG WR */
+       FRMR_FLUSHED_LI,        /* flushed LOCALINV WR */
 };
 
 struct rpcrdma_frmr {
index 0137af1c0916cdf25547f89ed20b62588fc5c0b2..e01c825bc68338bff19e4f5ec3763d581f5a58ce 100644 (file)
@@ -2563,6 +2563,7 @@ static int bc_malloc(struct rpc_task *task)
        buf->len = PAGE_SIZE;
 
        rqst->rq_buffer = buf->data;
+       rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize;
        return 0;
 }
 
index 02beb35f577fca17e8989c7b63699a62bef8797d..3b95fe980fa27e8cf97bedac9b7b46e7f8fe4e2d 100644 (file)
@@ -771,6 +771,9 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
        u32 mask = BR_LEARNING | BR_LEARNING_SYNC | BR_FLOOD;
        int err;
 
+       if (!netif_is_bridge_port(dev))
+               return -EOPNOTSUPP;
+
        err = switchdev_port_attr_get(dev, &attr);
        if (err && err != -EOPNOTSUPP)
                return err;
@@ -926,6 +929,9 @@ int switchdev_port_bridge_setlink(struct net_device *dev,
        struct nlattr *afspec;
        int err = 0;
 
+       if (!netif_is_bridge_port(dev))
+               return -EOPNOTSUPP;
+
        protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg),
                                   IFLA_PROTINFO);
        if (protinfo) {
@@ -959,6 +965,9 @@ int switchdev_port_bridge_dellink(struct net_device *dev,
 {
        struct nlattr *afspec;
 
+       if (!netif_is_bridge_port(dev))
+               return -EOPNOTSUPP;
+
        afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg),
                                 IFLA_AF_SPEC);
        if (afspec)
index 753f774cb46f39a7280515ca64c8c41897d9a480..aa1babbea385348f1ecd4b7467079fc442653094 100644 (file)
@@ -247,11 +247,17 @@ int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb)
  *
  * RCU is locked, no other locks set
  */
-void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, u32 acked)
+void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
+                       struct tipc_msg *hdr)
 {
        struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
+       u16 acked = msg_bcast_ack(hdr);
        struct sk_buff_head xmitq;
 
+       /* Ignore bc acks sent by peer before bcast synch point was received */
+       if (msg_bc_ack_invalid(hdr))
+               return;
+
        __skb_queue_head_init(&xmitq);
 
        tipc_bcast_lock(net);
@@ -279,11 +285,11 @@ int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
        __skb_queue_head_init(&xmitq);
 
        tipc_bcast_lock(net);
-       if (msg_type(hdr) == STATE_MSG) {
+       if (msg_type(hdr) != STATE_MSG) {
+               tipc_link_bc_init_rcv(l, hdr);
+       } else if (!msg_bc_ack_invalid(hdr)) {
                tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq);
                rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq);
-       } else {
-               tipc_link_bc_init_rcv(l, hdr);
        }
        tipc_bcast_unlock(net);
 
index 5ffe34472ccd091d19e92137c379191b0d596844..855d53c64ab347ec5b37dc06a39e10748f7bf388 100644 (file)
@@ -55,7 +55,8 @@ void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id);
 int  tipc_bcast_get_mtu(struct net *net);
 int tipc_bcast_xmit(struct net *net, struct sk_buff_head *list);
 int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb);
-void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, u32 acked);
+void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
+                       struct tipc_msg *hdr);
 int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
                        struct tipc_msg *hdr);
 int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg);
index 975dbeb60ab0461ba16094099382ec98cec945d7..52d74760fb68697d508fafb213b56deaed2e8639 100644 (file)
@@ -421,6 +421,10 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
        dev = dev_get_by_name(net, driver_name);
        if (!dev)
                return -ENODEV;
+       if (tipc_mtu_bad(dev, 0)) {
+               dev_put(dev);
+               return -EINVAL;
+       }
 
        /* Associate TIPC bearer with L2 bearer */
        rcu_assign_pointer(b->media_ptr, dev);
@@ -610,8 +614,6 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
        if (!b)
                return NOTIFY_DONE;
 
-       b->mtu = dev->mtu;
-
        switch (evt) {
        case NETDEV_CHANGE:
                if (netif_carrier_ok(dev))
@@ -624,6 +626,11 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
                tipc_reset_bearer(net, b);
                break;
        case NETDEV_CHANGEMTU:
+               if (tipc_mtu_bad(dev, 0)) {
+                       bearer_disable(net, b);
+                       break;
+               }
+               b->mtu = dev->mtu;
                tipc_reset_bearer(net, b);
                break;
        case NETDEV_CHANGEADDR:
index 78892e2f53e306e09cd788e0330c01eddb8df294..278ff7f616f9e884aca58fce761a23cfd1c55f70 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "netlink.h"
 #include "core.h"
+#include "msg.h"
 #include <net/genetlink.h>
 
 #define MAX_MEDIA      3
@@ -59,6 +60,9 @@
 #define TIPC_MEDIA_TYPE_IB     2
 #define TIPC_MEDIA_TYPE_UDP    3
 
+/* minimum bearer MTU */
+#define TIPC_MIN_BEARER_MTU    (MAX_H_SIZE + INT_H_SIZE)
+
 /**
  * struct tipc_media_addr - destination address used by TIPC bearers
  * @value: address info (format defined by media)
@@ -215,4 +219,13 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
 void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
                         struct sk_buff_head *xmitq);
 
+/* check if device MTU is too low for tipc headers */
+static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve)
+{
+       if (dev->mtu >= TIPC_MIN_BEARER_MTU + reserve)
+               return false;
+       netdev_warn(dev, "MTU too low for tipc bearer\n");
+       return true;
+}
+
 #endif /* _TIPC_BEARER_H */
index b36e16cdc945230f0460f46ef5c4fb60e8b8c745..bda89bf9f4ff185f64c68c06d8b88a4385380c58 100644 (file)
@@ -47,8 +47,8 @@
 #include <linux/pkt_sched.h>
 
 struct tipc_stats {
-       u32 sent_info;          /* used in counting # sent packets */
-       u32 recv_info;          /* used in counting # recv'd packets */
+       u32 sent_pkts;
+       u32 recv_pkts;
        u32 sent_states;
        u32 recv_states;
        u32 sent_probes;
@@ -857,7 +857,6 @@ void tipc_link_reset(struct tipc_link *l)
        l->acked = 0;
        l->silent_intv_cnt = 0;
        l->rst_cnt = 0;
-       l->stats.recv_info = 0;
        l->stale_count = 0;
        l->bc_peer_is_up = false;
        memset(&l->mon_state, 0, sizeof(l->mon_state));
@@ -888,6 +887,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
        struct sk_buff_head *transmq = &l->transmq;
        struct sk_buff_head *backlogq = &l->backlogq;
        struct sk_buff *skb, *_skb, *bskb;
+       int pkt_cnt = skb_queue_len(list);
 
        /* Match msg importance against this and all higher backlog limits: */
        if (!skb_queue_empty(backlogq)) {
@@ -901,6 +901,11 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
                return -EMSGSIZE;
        }
 
+       if (pkt_cnt > 1) {
+               l->stats.sent_fragmented++;
+               l->stats.sent_fragments += pkt_cnt;
+       }
+
        /* Prepare each packet for sending, and add to relevant queue: */
        while (skb_queue_len(list)) {
                skb = skb_peek(list);
@@ -920,6 +925,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
                        __skb_queue_tail(xmitq, _skb);
                        TIPC_SKB_CB(skb)->ackers = l->ackers;
                        l->rcv_unacked = 0;
+                       l->stats.sent_pkts++;
                        seqno++;
                        continue;
                }
@@ -968,6 +974,7 @@ void tipc_link_advance_backlog(struct tipc_link *l, struct sk_buff_head *xmitq)
                msg_set_ack(hdr, ack);
                msg_set_bcast_ack(hdr, bc_ack);
                l->rcv_unacked = 0;
+               l->stats.sent_pkts++;
                seqno++;
        }
        l->snd_nxt = seqno;
@@ -1260,7 +1267,7 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,
 
                /* Deliver packet */
                l->rcv_nxt++;
-               l->stats.recv_info++;
+               l->stats.recv_pkts++;
                if (!tipc_data_input(l, skb, l->inputq))
                        rc |= tipc_link_input(l, skb, l->inputq);
                if (unlikely(++l->rcv_unacked >= TIPC_MIN_LINK_WIN))
@@ -1312,6 +1319,7 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
        msg_set_next_sent(hdr, l->snd_nxt);
        msg_set_ack(hdr, l->rcv_nxt - 1);
        msg_set_bcast_ack(hdr, bcl->rcv_nxt - 1);
+       msg_set_bc_ack_invalid(hdr, !node_up);
        msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1);
        msg_set_link_tolerance(hdr, tolerance);
        msg_set_linkprio(hdr, priority);
@@ -1491,8 +1499,9 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
                if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL))
                        l->tolerance = peers_tol;
 
-               if (peers_prio && in_range(peers_prio, TIPC_MIN_LINK_PRI,
-                                          TIPC_MAX_LINK_PRI)) {
+               /* Update own prio if peer indicates a different value */
+               if ((peers_prio != l->priority) &&
+                   in_range(peers_prio, 1, TIPC_MAX_LINK_PRI)) {
                        l->priority = peers_prio;
                        rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
                }
@@ -1574,6 +1583,7 @@ static void tipc_link_build_bc_init_msg(struct tipc_link *l,
        __skb_queue_head_init(&list);
        if (!tipc_link_build_bc_proto_msg(l->bc_rcvlink, false, 0, &list))
                return;
+       msg_set_bc_ack_invalid(buf_msg(skb_peek(&list)), true);
        tipc_link_xmit(l, &list, xmitq);
 }
 
@@ -1797,10 +1807,6 @@ void tipc_link_set_queue_limits(struct tipc_link *l, u32 win)
 void tipc_link_reset_stats(struct tipc_link *l)
 {
        memset(&l->stats, 0, sizeof(l->stats));
-       if (!link_is_bc_sndlink(l)) {
-               l->stats.sent_info = l->snd_nxt;
-               l->stats.recv_info = l->rcv_nxt;
-       }
 }
 
 static void link_print(struct tipc_link *l, const char *str)
@@ -1864,12 +1870,12 @@ static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s)
        };
 
        struct nla_map map[] = {
-               {TIPC_NLA_STATS_RX_INFO, s->recv_info},
+               {TIPC_NLA_STATS_RX_INFO, 0},
                {TIPC_NLA_STATS_RX_FRAGMENTS, s->recv_fragments},
                {TIPC_NLA_STATS_RX_FRAGMENTED, s->recv_fragmented},
                {TIPC_NLA_STATS_RX_BUNDLES, s->recv_bundles},
                {TIPC_NLA_STATS_RX_BUNDLED, s->recv_bundled},
-               {TIPC_NLA_STATS_TX_INFO, s->sent_info},
+               {TIPC_NLA_STATS_TX_INFO, 0},
                {TIPC_NLA_STATS_TX_FRAGMENTS, s->sent_fragments},
                {TIPC_NLA_STATS_TX_FRAGMENTED, s->sent_fragmented},
                {TIPC_NLA_STATS_TX_BUNDLES, s->sent_bundles},
@@ -1944,9 +1950,9 @@ int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,
                goto attr_msg_full;
        if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->mtu))
                goto attr_msg_full;
-       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->rcv_nxt))
+       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->stats.recv_pkts))
                goto attr_msg_full;
-       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, link->snd_nxt))
+       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, link->stats.sent_pkts))
                goto attr_msg_full;
 
        if (tipc_link_is_up(link))
@@ -2001,12 +2007,12 @@ static int __tipc_nl_add_bc_link_stat(struct sk_buff *skb,
        };
 
        struct nla_map map[] = {
-               {TIPC_NLA_STATS_RX_INFO, stats->recv_info},
+               {TIPC_NLA_STATS_RX_INFO, stats->recv_pkts},
                {TIPC_NLA_STATS_RX_FRAGMENTS, stats->recv_fragments},
                {TIPC_NLA_STATS_RX_FRAGMENTED, stats->recv_fragmented},
                {TIPC_NLA_STATS_RX_BUNDLES, stats->recv_bundles},
                {TIPC_NLA_STATS_RX_BUNDLED, stats->recv_bundled},
-               {TIPC_NLA_STATS_TX_INFO, stats->sent_info},
+               {TIPC_NLA_STATS_TX_INFO, stats->sent_pkts},
                {TIPC_NLA_STATS_TX_FRAGMENTS, stats->sent_fragments},
                {TIPC_NLA_STATS_TX_FRAGMENTED, stats->sent_fragmented},
                {TIPC_NLA_STATS_TX_BUNDLES, stats->sent_bundles},
@@ -2073,9 +2079,9 @@ int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg)
                goto attr_msg_full;
        if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, bcl->name))
                goto attr_msg_full;
-       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, bcl->rcv_nxt))
+       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, 0))
                goto attr_msg_full;
-       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, bcl->snd_nxt))
+       if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, 0))
                goto attr_msg_full;
 
        prop = nla_nest_start(msg->skb, TIPC_NLA_LINK_PROP);
index ed97a5876ebef128937906d4115d3c1db6d16998..9e109bb1a2071836323d41b77e903644b28c7b73 100644 (file)
@@ -455,14 +455,14 @@ void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
        int i, applied_bef;
 
        state->probing = false;
-       if (!dlen)
-               return;
 
        /* Sanity check received domain record */
-       if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen) {
-               pr_warn_ratelimited("Received illegal domain record\n");
+       if (dlen < dom_rec_len(arrv_dom, 0))
+               return;
+       if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
+               return;
+       if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen)
                return;
-       }
 
        /* Synch generation numbers with peer if link just came up */
        if (!state->synched) {
index c3832cdf2278a3a49dd6624d350ba34096764897..50a739860d379ebaf775e566e67979dda6842e4d 100644 (file)
@@ -714,6 +714,23 @@ static inline void msg_set_peer_stopping(struct tipc_msg *m, u32 s)
        msg_set_bits(m, 5, 13, 0x1, s);
 }
 
+static inline bool msg_bc_ack_invalid(struct tipc_msg *m)
+{
+       switch (msg_user(m)) {
+       case BCAST_PROTOCOL:
+       case NAME_DISTRIBUTOR:
+       case LINK_PROTOCOL:
+               return msg_bits(m, 5, 14, 0x1);
+       default:
+               return false;
+       }
+}
+
+static inline void msg_set_bc_ack_invalid(struct tipc_msg *m, bool invalid)
+{
+       msg_set_bits(m, 5, 14, 0x1, invalid);
+}
+
 static inline char *msg_media_addr(struct tipc_msg *m)
 {
        return (char *)&m->hdr[TIPC_MEDIA_INFO_OFFSET];
index a04fe9be1c60e2a7c1cb2f90c80731e08dcc910d..c1cfd92de17aee30a310305707a70ecb87fd2548 100644 (file)
@@ -156,6 +156,7 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,
                                pr_warn("Bulk publication failure\n");
                                return;
                        }
+                       msg_set_bc_ack_invalid(buf_msg(skb), true);
                        item = (struct distr_item *)msg_data(buf_msg(skb));
                }
 
index 7ef14e2d2356590d72284e3ef056d63dee3d1b12..9d2f4c2b08abc56ecb627ff067ad359c54e735fd 100644 (file)
@@ -1535,7 +1535,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)
        if (unlikely(usr == LINK_PROTOCOL))
                tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq);
        else if (unlikely(tipc_link_acked(n->bc_entry.link) != bc_ack))
-               tipc_bcast_ack_rcv(net, n->bc_entry.link, bc_ack);
+               tipc_bcast_ack_rcv(net, n->bc_entry.link, hdr);
 
        /* Receive packet directly if conditions permit */
        tipc_node_read_lock(n);
index f9f5f3c3dab530c0b798d314873800500ccc30b5..41f013888f07a572a825ee7355291a00e400e272 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/socket.c: TIPC socket API
  *
- * Copyright (c) 2001-2007, 2012-2015, Ericsson AB
+ * Copyright (c) 2001-2007, 2012-2016, Ericsson AB
  * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -129,54 +129,8 @@ static const struct proto_ops packet_ops;
 static const struct proto_ops stream_ops;
 static const struct proto_ops msg_ops;
 static struct proto tipc_proto;
-
 static const struct rhashtable_params tsk_rht_params;
 
-/*
- * Revised TIPC socket locking policy:
- *
- * Most socket operations take the standard socket lock when they start
- * and hold it until they finish (or until they need to sleep).  Acquiring
- * this lock grants the owner exclusive access to the fields of the socket
- * data structures, with the exception of the backlog queue.  A few socket
- * operations can be done without taking the socket lock because they only
- * read socket information that never changes during the life of the socket.
- *
- * Socket operations may acquire the lock for the associated TIPC port if they
- * need to perform an operation on the port.  If any routine needs to acquire
- * both the socket lock and the port lock it must take the socket lock first
- * to avoid the risk of deadlock.
- *
- * The dispatcher handling incoming messages cannot grab the socket lock in
- * the standard fashion, since invoked it runs at the BH level and cannot block.
- * Instead, it checks to see if the socket lock is currently owned by someone,
- * and either handles the message itself or adds it to the socket's backlog
- * queue; in the latter case the queued message is processed once the process
- * owning the socket lock releases it.
- *
- * NOTE: Releasing the socket lock while an operation is sleeping overcomes
- * the problem of a blocked socket operation preventing any other operations
- * from occurring.  However, applications must be careful if they have
- * multiple threads trying to send (or receive) on the same socket, as these
- * operations might interfere with each other.  For example, doing a connect
- * and a receive at the same time might allow the receive to consume the
- * ACK message meant for the connect.  While additional work could be done
- * to try and overcome this, it doesn't seem to be worthwhile at the present.
- *
- * NOTE: Releasing the socket lock while an operation is sleeping also ensures
- * that another operation that must be performed in a non-blocking manner is
- * not delayed for very long because the lock has already been taken.
- *
- * NOTE: This code assumes that certain fields of a port/socket pair are
- * constant over its lifetime; such fields can be examined without taking
- * the socket lock and/or port lock, and do not need to be re-read even
- * after resuming processing after waiting.  These fields include:
- *   - socket type
- *   - pointer to socket sk structure (aka tipc_sock structure)
- *   - pointer to port structure
- *   - port reference
- */
-
 static u32 tsk_own_node(struct tipc_sock *tsk)
 {
        return msg_prevnode(&tsk->phdr);
@@ -232,7 +186,7 @@ static struct tipc_sock *tipc_sk(const struct sock *sk)
 
 static bool tsk_conn_cong(struct tipc_sock *tsk)
 {
-       return tsk->snt_unacked >= tsk->snd_win;
+       return tsk->snt_unacked > tsk->snd_win;
 }
 
 /* tsk_blocks(): translate a buffer size in bytes to number of
index 78cab9c5a445afd5a57a9b53d6960da533a12ea0..b58dc95f3d3535a305e529c75282360ea731f82d 100644 (file)
@@ -697,6 +697,11 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
                udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
                udp_conf.use_udp_checksums = false;
                ub->ifindex = dev->ifindex;
+               if (tipc_mtu_bad(dev, sizeof(struct iphdr) +
+                                     sizeof(struct udphdr))) {
+                       err = -EINVAL;
+                       goto err;
+               }
                b->mtu = dev->mtu - sizeof(struct iphdr)
                        - sizeof(struct udphdr);
 #if IS_ENABLED(CONFIG_IPV6)
index 145082e2ba36068192ccef517804a14aa0d08752..2358f2690ec58c20aeb77fb60ac45b3db27ecac6 100644 (file)
@@ -2199,7 +2199,8 @@ out:
  *     Sleep until more data has arrived. But check for races..
  */
 static long unix_stream_data_wait(struct sock *sk, long timeo,
-                                 struct sk_buff *last, unsigned int last_len)
+                                 struct sk_buff *last, unsigned int last_len,
+                                 bool freezable)
 {
        struct sk_buff *tail;
        DEFINE_WAIT(wait);
@@ -2220,7 +2221,10 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
 
                sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
                unix_state_unlock(sk);
-               timeo = freezable_schedule_timeout(timeo);
+               if (freezable)
+                       timeo = freezable_schedule_timeout(timeo);
+               else
+                       timeo = schedule_timeout(timeo);
                unix_state_lock(sk);
 
                if (sock_flag(sk, SOCK_DEAD))
@@ -2250,7 +2254,8 @@ struct unix_stream_read_state {
        unsigned int splice_flags;
 };
 
-static int unix_stream_read_generic(struct unix_stream_read_state *state)
+static int unix_stream_read_generic(struct unix_stream_read_state *state,
+                                   bool freezable)
 {
        struct scm_cookie scm;
        struct socket *sock = state->socket;
@@ -2330,7 +2335,7 @@ again:
                        mutex_unlock(&u->iolock);
 
                        timeo = unix_stream_data_wait(sk, timeo, last,
-                                                     last_len);
+                                                     last_len, freezable);
 
                        if (signal_pending(current)) {
                                err = sock_intr_errno(timeo);
@@ -2472,7 +2477,7 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg,
                .flags = flags
        };
 
-       return unix_stream_read_generic(&state);
+       return unix_stream_read_generic(&state, true);
 }
 
 static int unix_stream_splice_actor(struct sk_buff *skb,
@@ -2503,7 +2508,7 @@ static ssize_t unix_stream_splice_read(struct socket *sock,  loff_t *ppos,
            flags & SPLICE_F_NONBLOCK)
                state.flags = MSG_DONTWAIT;
 
-       return unix_stream_read_generic(&state);
+       return unix_stream_read_generic(&state, false);
 }
 
 static int unix_shutdown(struct socket *sock, int mode)
@@ -2812,7 +2817,8 @@ static int unix_seq_show(struct seq_file *seq, void *v)
                                i++;
                        }
                        for ( ; i < len; i++)
-                               seq_putc(seq, u->addr->name->sun_path[i]);
+                               seq_putc(seq, u->addr->name->sun_path[i] ?:
+                                        '@');
                }
                unix_state_unlock(s);
                seq_putc(seq, '\n');
index 08d2e948c9ad306a0ed40531efc4103877b9f4ae..f0c0c8a48c920887cadbc714f3e55015e9b9761d 100644 (file)
@@ -71,6 +71,7 @@ struct cfg80211_registered_device {
        struct list_head bss_list;
        struct rb_root bss_tree;
        u32 bss_generation;
+       u32 bss_entries;
        struct cfg80211_scan_request *scan_req; /* protected by RTNL */
        struct sk_buff *scan_msg;
        struct cfg80211_sched_scan_request __rcu *sched_scan_req;
index b5bd58d0f73129104e32a07155b03f915c343d54..35ad69fd08383a2a8392170d2a580fc4549276d7 100644 (file)
  * also linked into the probe response struct.
  */
 
+/*
+ * Limit the number of BSS entries stored in mac80211. Each one is
+ * a bit over 4k at most, so this limits to roughly 4-5M of memory.
+ * If somebody wants to really attack this though, they'd likely
+ * use small beacons, and only one type of frame, limiting each of
+ * the entries to a much smaller size (in order to generate more
+ * entries in total, so overhead is bigger.)
+ */
+static int bss_entries_limit = 1000;
+module_param(bss_entries_limit, int, 0644);
+MODULE_PARM_DESC(bss_entries_limit,
+                 "limit to number of scan BSS entries (per wiphy, default 1000)");
+
 #define IEEE80211_SCAN_RESULT_EXPIRE   (30 * HZ)
 
 static void bss_free(struct cfg80211_internal_bss *bss)
@@ -137,6 +150,10 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
 
        list_del_init(&bss->list);
        rb_erase(&bss->rbn, &rdev->bss_tree);
+       rdev->bss_entries--;
+       WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
+                 "rdev bss entries[%d]/list[empty:%d] corruption\n",
+                 rdev->bss_entries, list_empty(&rdev->bss_list));
        bss_ref_put(rdev, bss);
        return true;
 }
@@ -163,6 +180,40 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
                rdev->bss_generation++;
 }
 
+static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev)
+{
+       struct cfg80211_internal_bss *bss, *oldest = NULL;
+       bool ret;
+
+       lockdep_assert_held(&rdev->bss_lock);
+
+       list_for_each_entry(bss, &rdev->bss_list, list) {
+               if (atomic_read(&bss->hold))
+                       continue;
+
+               if (!list_empty(&bss->hidden_list) &&
+                   !bss->pub.hidden_beacon_bss)
+                       continue;
+
+               if (oldest && time_before(oldest->ts, bss->ts))
+                       continue;
+               oldest = bss;
+       }
+
+       if (WARN_ON(!oldest))
+               return false;
+
+       /*
+        * The callers make sure to increase rdev->bss_generation if anything
+        * gets removed (and a new entry added), so there's no need to also do
+        * it here.
+        */
+
+       ret = __cfg80211_unlink_bss(rdev, oldest);
+       WARN_ON(!ret);
+       return ret;
+}
+
 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
                           bool send_message)
 {
@@ -689,6 +740,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
        const u8 *ie;
        int i, ssidlen;
        u8 fold = 0;
+       u32 n_entries = 0;
 
        ies = rcu_access_pointer(new->pub.beacon_ies);
        if (WARN_ON(!ies))
@@ -712,6 +764,12 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
        /* This is the bad part ... */
 
        list_for_each_entry(bss, &rdev->bss_list, list) {
+               /*
+                * we're iterating all the entries anyway, so take the
+                * opportunity to validate the list length accounting
+                */
+               n_entries++;
+
                if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
                        continue;
                if (bss->pub.channel != new->pub.channel)
@@ -740,6 +798,10 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
                                   new->pub.beacon_ies);
        }
 
+       WARN_ONCE(n_entries != rdev->bss_entries,
+                 "rdev bss entries[%d]/list[len:%d] corruption\n",
+                 rdev->bss_entries, n_entries);
+
        return true;
 }
 
@@ -894,7 +956,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
                        }
                }
 
+               if (rdev->bss_entries >= bss_entries_limit &&
+                   !cfg80211_bss_expire_oldest(rdev)) {
+                       kfree(new);
+                       goto drop;
+               }
+
                list_add_tail(&new->list, &rdev->bss_list);
+               rdev->bss_entries++;
                rb_insert_bss(rdev, new);
                found = new;
        }
index 0082f4b01795a1c80cbf453e7767893a1caf4dd5..14b3f007826d91da6c5a71aee105b735eb9a2071 100644 (file)
@@ -104,13 +104,16 @@ static int wiphy_suspend(struct device *dev)
 
        rtnl_lock();
        if (rdev->wiphy.registered) {
-               if (!rdev->wiphy.wowlan_config)
+               if (!rdev->wiphy.wowlan_config) {
                        cfg80211_leave_all(rdev);
+                       cfg80211_process_rdev_events(rdev);
+               }
                if (rdev->ops->suspend)
                        ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config);
                if (ret == 1) {
                        /* Driver refuse to configure wowlan */
                        cfg80211_leave_all(rdev);
+                       cfg80211_process_rdev_events(rdev);
                        ret = rdev_suspend(rdev, NULL);
                }
        }
index 8edce22d1b9316bf79e99411ffe3ce66e3ae0a6f..659b507b347d6a5d183baab16665ace0a03ae672 100644 (file)
@@ -420,8 +420,8 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
 }
 EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
 
-static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
-                                   const u8 *addr, enum nl80211_iftype iftype)
+int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+                                 const u8 *addr, enum nl80211_iftype iftype)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct {
@@ -525,13 +525,7 @@ static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
 
        return 0;
 }
-
-int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
-                          enum nl80211_iftype iftype)
-{
-       return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
-}
-EXPORT_SYMBOL(ieee80211_data_to_8023);
+EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
 
 int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                             enum nl80211_iftype iftype,
@@ -746,24 +740,18 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
                              const u8 *addr, enum nl80211_iftype iftype,
                              const unsigned int extra_headroom,
-                             bool has_80211_header)
+                             const u8 *check_da, const u8 *check_sa)
 {
        unsigned int hlen = ALIGN(extra_headroom, 4);
        struct sk_buff *frame = NULL;
        u16 ethertype;
        u8 *payload;
-       int offset = 0, remaining, err;
+       int offset = 0, remaining;
        struct ethhdr eth;
        bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
        bool reuse_skb = false;
        bool last = false;
 
-       if (has_80211_header) {
-               err = __ieee80211_data_to_8023(skb, &eth, addr, iftype);
-               if (err)
-                       goto out;
-       }
-
        while (!last) {
                unsigned int subframe_len;
                int len;
@@ -780,8 +768,17 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
                        goto purge;
 
                offset += sizeof(struct ethhdr);
-               /* reuse skb for the last subframe */
                last = remaining <= subframe_len + padding;
+
+               /* FIXME: should we really accept multicast DA? */
+               if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
+                    !ether_addr_equal(check_da, eth.h_dest)) ||
+                   (check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
+                       offset += len + padding;
+                       continue;
+               }
+
+               /* reuse skb for the last subframe */
                if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
                        skb_pull(skb, offset);
                        frame = skb;
@@ -819,7 +816,6 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 
  purge:
        __skb_queue_purge(list);
- out:
        dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
@@ -1162,7 +1158,8 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
                   58500000,
                   65000000,
                   78000000,
-                  0,
+               /* not in the spec, but some devices use this: */
+                  86500000,
                },
                {  13500000,
                   27000000,
index fd6986634e6fe4dc77993854323d7558637b94bc..5bf7e1bfeac7aa26549cdcac42ddf7cda5a3ad88 100644 (file)
@@ -1268,12 +1268,14 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
                        err = security_xfrm_policy_lookup(pol->security,
                                                      fl->flowi_secid,
                                                      policy_to_flow_dir(dir));
-                       if (!err && !xfrm_pol_hold_rcu(pol))
-                               goto again;
-                       else if (err == -ESRCH)
+                       if (!err) {
+                               if (!xfrm_pol_hold_rcu(pol))
+                                       goto again;
+                       } else if (err == -ESRCH) {
                                pol = NULL;
-                       else
+                       } else {
                                pol = ERR_PTR(err);
+                       }
                } else
                        pol = NULL;
        }
index 08892091cfe3a65c13994b2743586f5137c89fd9..671a1d0333f0d2c828c757944016cbe48836ec72 100644 (file)
@@ -2450,7 +2450,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
 #ifdef CONFIG_COMPAT
        if (in_compat_syscall())
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 #endif
 
        type = nlh->nlmsg_type;
index 12b7304d55dcd2e64515c6a0af7c777a44f3e645..72c58675973e65bf7d0e503dff1ed28774cebc07 100644 (file)
@@ -27,6 +27,7 @@ hostprogs-y += xdp2
 hostprogs-y += test_current_task_under_cgroup
 hostprogs-y += trace_event
 hostprogs-y += sampleip
+hostprogs-y += tc_l2_redirect
 
 test_verifier-objs := test_verifier.o libbpf.o
 test_maps-objs := test_maps.o libbpf.o
@@ -56,6 +57,7 @@ test_current_task_under_cgroup-objs := bpf_load.o libbpf.o \
                                       test_current_task_under_cgroup_user.o
 trace_event-objs := bpf_load.o libbpf.o trace_event_user.o
 sampleip-objs := bpf_load.o libbpf.o sampleip_user.o
+tc_l2_redirect-objs := bpf_load.o libbpf.o tc_l2_redirect_user.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -72,6 +74,7 @@ always += test_probe_write_user_kern.o
 always += trace_output_kern.o
 always += tcbpf1_kern.o
 always += tcbpf2_kern.o
+always += tc_l2_redirect_kern.o
 always += lathist_kern.o
 always += offwaketime_kern.o
 always += spintest_kern.o
@@ -111,6 +114,7 @@ HOSTLOADLIBES_xdp2 += -lelf
 HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
 HOSTLOADLIBES_trace_event += -lelf
 HOSTLOADLIBES_sampleip += -lelf
+HOSTLOADLIBES_tc_l2_redirect += -l elf
 
 # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
 #  make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
index 90f44bd2045e16f5dd78ed842381d25a06fffa82..dadd5161bd916a0e7f470d211ffbce00af3cb7d0 100644 (file)
@@ -113,7 +113,7 @@ static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) =
 #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */
 #define PT_REGS_RC(x) ((x)->gprs[2])
 #define PT_REGS_SP(x) ((x)->gprs[15])
-#define PT_REGS_IP(x) ((x)->ip)
+#define PT_REGS_IP(x) ((x)->psw.addr)
 
 #elif defined(__aarch64__)
 
index d17550198d0628e063e43a64253ec335a012c28f..6db6b21fdc6dd71fd230cfbc40161d087c92024f 100644 (file)
@@ -4,6 +4,7 @@
  * modify it under the terms of version 2 of the GNU General Public
  * License as published by the Free Software Foundation.
  */
+#define KBUILD_MODNAME "foo"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/in.h>
index cf2511c33905751bb6ed866bf6bba9b1fb8330f3..10af53d33cc2925a928fe496fdc1047629b998e3 100644 (file)
@@ -4,6 +4,7 @@
  * modify it under the terms of version 2 of the GNU General Public
  * License as published by the Free Software Foundation.
  */
+#define KBUILD_MODNAME "foo"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/in.h>
index edab34dce79b3794b010ca4138ef969d13c68535..95c16324760c0be1af8be927e1adffae0b582525 100644 (file)
@@ -4,6 +4,7 @@
  * modify it under the terms of version 2 of the GNU General Public
  * License as published by the Free Software Foundation.
  */
+#define KBUILD_MODNAME "foo"
 #include <linux/if_ether.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
index 774a681f374a9781f44f9c0715adb126b47b999d..ceabf31079cf5ef7db360b1182ab64e78d4c05ef 100644 (file)
@@ -25,7 +25,7 @@ int do_sample(struct bpf_perf_event_data *ctx)
        u64 ip;
        u32 *value, init_val = 1;
 
-       ip = ctx->regs.ip;
+       ip = PT_REGS_IP(&ctx->regs);
        value = bpf_map_lookup_elem(&ip_map, &ip);
        if (value)
                *value += 1;
diff --git a/samples/bpf/tc_l2_redirect.sh b/samples/bpf/tc_l2_redirect.sh
new file mode 100755 (executable)
index 0000000..80a0559
--- /dev/null
@@ -0,0 +1,173 @@
+#!/bin/bash
+
+[[ -z $TC ]] && TC='tc'
+[[ -z $IP ]] && IP='ip'
+
+REDIRECT_USER='./tc_l2_redirect'
+REDIRECT_BPF='./tc_l2_redirect_kern.o'
+
+RP_FILTER=$(< /proc/sys/net/ipv4/conf/all/rp_filter)
+IPV6_FORWARDING=$(< /proc/sys/net/ipv6/conf/all/forwarding)
+
+function config_common {
+       local tun_type=$1
+
+       $IP netns add ns1
+       $IP netns add ns2
+       $IP link add ve1 type veth peer name vens1
+       $IP link add ve2 type veth peer name vens2
+       $IP link set dev ve1 up
+       $IP link set dev ve2 up
+       $IP link set dev ve1 mtu 1500
+       $IP link set dev ve2 mtu 1500
+       $IP link set dev vens1 netns ns1
+       $IP link set dev vens2 netns ns2
+
+       $IP -n ns1 link set dev lo up
+       $IP -n ns1 link set dev vens1 up
+       $IP -n ns1 addr add 10.1.1.101/24 dev vens1
+       $IP -n ns1 addr add 2401:db01::65/64 dev vens1 nodad
+       $IP -n ns1 route add default via 10.1.1.1 dev vens1
+       $IP -n ns1 route add default via 2401:db01::1 dev vens1
+
+       $IP -n ns2 link set dev lo up
+       $IP -n ns2 link set dev vens2 up
+       $IP -n ns2 addr add 10.2.1.102/24 dev vens2
+       $IP -n ns2 addr add 2401:db02::66/64 dev vens2 nodad
+       $IP -n ns2 addr add 10.10.1.102 dev lo
+       $IP -n ns2 addr add 2401:face::66/64 dev lo nodad
+       $IP -n ns2 link add ipt2 type ipip local 10.2.1.102 remote 10.2.1.1
+       $IP -n ns2 link add ip6t2 type ip6tnl mode any local 2401:db02::66 remote 2401:db02::1
+       $IP -n ns2 link set dev ipt2 up
+       $IP -n ns2 link set dev ip6t2 up
+       $IP netns exec ns2 $TC qdisc add dev vens2 clsact
+       $IP netns exec ns2 $TC filter add dev vens2 ingress bpf da obj $REDIRECT_BPF sec drop_non_tun_vip
+       if [[ $tun_type == "ipip" ]]; then
+               $IP -n ns2 route add 10.1.1.0/24 dev ipt2
+               $IP netns exec ns2 sysctl -q -w net.ipv4.conf.all.rp_filter=0
+               $IP netns exec ns2 sysctl -q -w net.ipv4.conf.ipt2.rp_filter=0
+       else
+               $IP -n ns2 route add 10.1.1.0/24 dev ip6t2
+               $IP -n ns2 route add 2401:db01::/64 dev ip6t2
+               $IP netns exec ns2 sysctl -q -w net.ipv4.conf.all.rp_filter=0
+               $IP netns exec ns2 sysctl -q -w net.ipv4.conf.ip6t2.rp_filter=0
+       fi
+
+       $IP addr add 10.1.1.1/24 dev ve1
+       $IP addr add 2401:db01::1/64 dev ve1 nodad
+       $IP addr add 10.2.1.1/24 dev ve2
+       $IP addr add 2401:db02::1/64 dev ve2 nodad
+
+       $TC qdisc add dev ve2 clsact
+       $TC filter add dev ve2 ingress bpf da obj $REDIRECT_BPF sec l2_to_iptun_ingress_forward
+
+       sysctl -q -w net.ipv4.conf.all.rp_filter=0
+       sysctl -q -w net.ipv6.conf.all.forwarding=1
+}
+
+function cleanup {
+       set +e
+       [[ -z $DEBUG ]] || set +x
+       $IP netns delete ns1 >& /dev/null
+       $IP netns delete ns2 >& /dev/null
+       $IP link del ve1 >& /dev/null
+       $IP link del ve2 >& /dev/null
+       $IP link del ipt >& /dev/null
+       $IP link del ip6t >& /dev/null
+       sysctl -q -w net.ipv4.conf.all.rp_filter=$RP_FILTER
+       sysctl -q -w net.ipv6.conf.all.forwarding=$IPV6_FORWARDING
+       rm -f /sys/fs/bpf/tc/globals/tun_iface
+       [[ -z $DEBUG ]] || set -x
+       set -e
+}
+
+function l2_to_ipip {
+       echo -n "l2_to_ipip $1: "
+
+       local dir=$1
+
+       config_common ipip
+
+       $IP link add ipt type ipip external
+       $IP link set dev ipt up
+       sysctl -q -w net.ipv4.conf.ipt.rp_filter=0
+       sysctl -q -w net.ipv4.conf.ipt.forwarding=1
+
+       if [[ $dir == "egress" ]]; then
+               $IP route add 10.10.1.0/24 via 10.2.1.102 dev ve2
+               $TC filter add dev ve2 egress bpf da obj $REDIRECT_BPF sec l2_to_iptun_ingress_redirect
+               sysctl -q -w net.ipv4.conf.ve1.forwarding=1
+       else
+               $TC qdisc add dev ve1 clsact
+               $TC filter add dev ve1 ingress bpf da obj $REDIRECT_BPF sec l2_to_iptun_ingress_redirect
+       fi
+
+       $REDIRECT_USER -U /sys/fs/bpf/tc/globals/tun_iface -i $(< /sys/class/net/ipt/ifindex)
+
+       $IP netns exec ns1 ping -c1 10.10.1.102 >& /dev/null
+
+       if [[ $dir == "egress" ]]; then
+               # test direct egress to ve2 (i.e. not forwarding from
+               # ve1 to ve2).
+               ping -c1 10.10.1.102 >& /dev/null
+       fi
+
+       cleanup
+
+       echo "OK"
+}
+
+function l2_to_ip6tnl {
+       echo -n "l2_to_ip6tnl $1: "
+
+       local dir=$1
+
+       config_common ip6tnl
+
+       $IP link add ip6t type ip6tnl mode any external
+       $IP link set dev ip6t up
+       sysctl -q -w net.ipv4.conf.ip6t.rp_filter=0
+       sysctl -q -w net.ipv4.conf.ip6t.forwarding=1
+
+       if [[ $dir == "egress" ]]; then
+               $IP route add 10.10.1.0/24 via 10.2.1.102 dev ve2
+               $IP route add 2401:face::/64 via 2401:db02::66 dev ve2
+               $TC filter add dev ve2 egress bpf da obj $REDIRECT_BPF sec l2_to_ip6tun_ingress_redirect
+               sysctl -q -w net.ipv4.conf.ve1.forwarding=1
+       else
+               $TC qdisc add dev ve1 clsact
+               $TC filter add dev ve1 ingress bpf da obj $REDIRECT_BPF sec l2_to_ip6tun_ingress_redirect
+       fi
+
+       $REDIRECT_USER -U /sys/fs/bpf/tc/globals/tun_iface -i $(< /sys/class/net/ip6t/ifindex)
+
+       $IP netns exec ns1 ping -c1 10.10.1.102 >& /dev/null
+       $IP netns exec ns1 ping -6 -c1 2401:face::66 >& /dev/null
+
+       if [[ $dir == "egress" ]]; then
+               # test direct egress to ve2 (i.e. not forwarding from
+               # ve1 to ve2).
+               ping -c1 10.10.1.102 >& /dev/null
+               ping -6 -c1 2401:face::66 >& /dev/null
+       fi
+
+       cleanup
+
+       echo "OK"
+}
+
+cleanup
+test_names="l2_to_ipip l2_to_ip6tnl"
+test_dirs="ingress egress"
+if [[ $# -ge 2 ]]; then
+       test_names=$1
+       test_dirs=$2
+elif [[ $# -ge 1 ]]; then
+       test_names=$1
+fi
+
+for t in $test_names; do
+       for d in $test_dirs; do
+               $t $d
+       done
+done
diff --git a/samples/bpf/tc_l2_redirect_kern.c b/samples/bpf/tc_l2_redirect_kern.c
new file mode 100644 (file)
index 0000000..92a4472
--- /dev/null
@@ -0,0 +1,236 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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 published by the Free Software Foundation.
+ */
+#include <uapi/linux/bpf.h>
+#include <uapi/linux/if_ether.h>
+#include <uapi/linux/if_packet.h>
+#include <uapi/linux/ip.h>
+#include <uapi/linux/ipv6.h>
+#include <uapi/linux/in.h>
+#include <uapi/linux/tcp.h>
+#include <uapi/linux/filter.h>
+#include <uapi/linux/pkt_cls.h>
+#include <net/ipv6.h>
+#include "bpf_helpers.h"
+
+#define _htonl __builtin_bswap32
+
+#define PIN_GLOBAL_NS          2
+struct bpf_elf_map {
+       __u32 type;
+       __u32 size_key;
+       __u32 size_value;
+       __u32 max_elem;
+       __u32 flags;
+       __u32 id;
+       __u32 pinning;
+};
+
+/* copy of 'struct ethhdr' without __packed */
+struct eth_hdr {
+       unsigned char   h_dest[ETH_ALEN];
+       unsigned char   h_source[ETH_ALEN];
+       unsigned short  h_proto;
+};
+
+struct bpf_elf_map SEC("maps") tun_iface = {
+       .type = BPF_MAP_TYPE_ARRAY,
+       .size_key = sizeof(int),
+       .size_value = sizeof(int),
+       .pinning = PIN_GLOBAL_NS,
+       .max_elem = 1,
+};
+
+static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr)
+{
+       if (eth_proto == htons(ETH_P_IP))
+               return (_htonl(0xffffff00) & daddr) == _htonl(0x0a0a0100);
+       else if (eth_proto == htons(ETH_P_IPV6))
+               return (daddr == _htonl(0x2401face));
+
+       return false;
+}
+
+SEC("l2_to_iptun_ingress_forward")
+int _l2_to_iptun_ingress_forward(struct __sk_buff *skb)
+{
+       struct bpf_tunnel_key tkey = {};
+       void *data = (void *)(long)skb->data;
+       struct eth_hdr *eth = data;
+       void *data_end = (void *)(long)skb->data_end;
+       int key = 0, *ifindex;
+
+       int ret;
+
+       if (data + sizeof(*eth) > data_end)
+               return TC_ACT_OK;
+
+       ifindex = bpf_map_lookup_elem(&tun_iface, &key);
+       if (!ifindex)
+               return TC_ACT_OK;
+
+       if (eth->h_proto == htons(ETH_P_IP)) {
+               char fmt4[] = "ingress forward to ifindex:%d daddr4:%x\n";
+               struct iphdr *iph = data + sizeof(*eth);
+
+               if (data + sizeof(*eth) + sizeof(*iph) > data_end)
+                       return TC_ACT_OK;
+
+               if (iph->protocol != IPPROTO_IPIP)
+                       return TC_ACT_OK;
+
+               bpf_trace_printk(fmt4, sizeof(fmt4), *ifindex,
+                                _htonl(iph->daddr));
+               return bpf_redirect(*ifindex, BPF_F_INGRESS);
+       } else if (eth->h_proto == htons(ETH_P_IPV6)) {
+               char fmt6[] = "ingress forward to ifindex:%d daddr6:%x::%x\n";
+               struct ipv6hdr *ip6h = data + sizeof(*eth);
+
+               if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
+                       return TC_ACT_OK;
+
+               if (ip6h->nexthdr != IPPROTO_IPIP &&
+                   ip6h->nexthdr != IPPROTO_IPV6)
+                       return TC_ACT_OK;
+
+               bpf_trace_printk(fmt6, sizeof(fmt6), *ifindex,
+                                _htonl(ip6h->daddr.s6_addr32[0]),
+                                _htonl(ip6h->daddr.s6_addr32[3]));
+               return bpf_redirect(*ifindex, BPF_F_INGRESS);
+       }
+
+       return TC_ACT_OK;
+}
+
+SEC("l2_to_iptun_ingress_redirect")
+int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb)
+{
+       struct bpf_tunnel_key tkey = {};
+       void *data = (void *)(long)skb->data;
+       struct eth_hdr *eth = data;
+       void *data_end = (void *)(long)skb->data_end;
+       int key = 0, *ifindex;
+
+       int ret;
+
+       if (data + sizeof(*eth) > data_end)
+               return TC_ACT_OK;
+
+       ifindex = bpf_map_lookup_elem(&tun_iface, &key);
+       if (!ifindex)
+               return TC_ACT_OK;
+
+       if (eth->h_proto == htons(ETH_P_IP)) {
+               char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
+               struct iphdr *iph = data + sizeof(*eth);
+               __be32 daddr = iph->daddr;
+
+               if (data + sizeof(*eth) + sizeof(*iph) > data_end)
+                       return TC_ACT_OK;
+
+               if (!is_vip_addr(eth->h_proto, daddr))
+                       return TC_ACT_OK;
+
+               bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(daddr), *ifindex);
+       } else {
+               return TC_ACT_OK;
+       }
+
+       tkey.tunnel_id = 10000;
+       tkey.tunnel_ttl = 64;
+       tkey.remote_ipv4 = 0x0a020166; /* 10.2.1.102 */
+       bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), 0);
+       return bpf_redirect(*ifindex, 0);
+}
+
+SEC("l2_to_ip6tun_ingress_redirect")
+int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb)
+{
+       struct bpf_tunnel_key tkey = {};
+       void *data = (void *)(long)skb->data;
+       struct eth_hdr *eth = data;
+       void *data_end = (void *)(long)skb->data_end;
+       int key = 0, *ifindex;
+
+       if (data + sizeof(*eth) > data_end)
+               return TC_ACT_OK;
+
+       ifindex = bpf_map_lookup_elem(&tun_iface, &key);
+       if (!ifindex)
+               return TC_ACT_OK;
+
+       if (eth->h_proto == htons(ETH_P_IP)) {
+               char fmt4[] = "e/ingress redirect daddr4:%x to ifindex:%d\n";
+               struct iphdr *iph = data + sizeof(*eth);
+
+               if (data + sizeof(*eth) + sizeof(*iph) > data_end)
+                       return TC_ACT_OK;
+
+               if (!is_vip_addr(eth->h_proto, iph->daddr))
+                       return TC_ACT_OK;
+
+               bpf_trace_printk(fmt4, sizeof(fmt4), _htonl(iph->daddr),
+                                *ifindex);
+       } else if (eth->h_proto == htons(ETH_P_IPV6)) {
+               char fmt6[] = "e/ingress redirect daddr6:%x to ifindex:%d\n";
+               struct ipv6hdr *ip6h = data + sizeof(*eth);
+
+               if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
+                       return TC_ACT_OK;
+
+               if (!is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
+                       return TC_ACT_OK;
+
+               bpf_trace_printk(fmt6, sizeof(fmt6),
+                                _htonl(ip6h->daddr.s6_addr32[0]), *ifindex);
+       } else {
+               return TC_ACT_OK;
+       }
+
+       tkey.tunnel_id = 10000;
+       tkey.tunnel_ttl = 64;
+       /* 2401:db02:0:0:0:0:0:66 */
+       tkey.remote_ipv6[0] = _htonl(0x2401db02);
+       tkey.remote_ipv6[1] = 0;
+       tkey.remote_ipv6[2] = 0;
+       tkey.remote_ipv6[3] = _htonl(0x00000066);
+       bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), BPF_F_TUNINFO_IPV6);
+       return bpf_redirect(*ifindex, 0);
+}
+
+SEC("drop_non_tun_vip")
+int _drop_non_tun_vip(struct __sk_buff *skb)
+{
+       struct bpf_tunnel_key tkey = {};
+       void *data = (void *)(long)skb->data;
+       struct eth_hdr *eth = data;
+       void *data_end = (void *)(long)skb->data_end;
+
+       if (data + sizeof(*eth) > data_end)
+               return TC_ACT_OK;
+
+       if (eth->h_proto == htons(ETH_P_IP)) {
+               struct iphdr *iph = data + sizeof(*eth);
+
+               if (data + sizeof(*eth) + sizeof(*iph) > data_end)
+                       return TC_ACT_OK;
+
+               if (is_vip_addr(eth->h_proto, iph->daddr))
+                       return TC_ACT_SHOT;
+       } else if (eth->h_proto == htons(ETH_P_IPV6)) {
+               struct ipv6hdr *ip6h = data + sizeof(*eth);
+
+               if (data + sizeof(*eth) + sizeof(*ip6h) > data_end)
+                       return TC_ACT_OK;
+
+               if (is_vip_addr(eth->h_proto, ip6h->daddr.s6_addr32[0]))
+                       return TC_ACT_SHOT;
+       }
+
+       return TC_ACT_OK;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/tc_l2_redirect_user.c b/samples/bpf/tc_l2_redirect_user.c
new file mode 100644 (file)
index 0000000..4013c53
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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 published by the Free Software Foundation.
+ */
+#include <linux/unistd.h>
+#include <linux/bpf.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libbpf.h"
+
+static void usage(void)
+{
+       printf("Usage: tc_l2_ipip_redirect [...]\n");
+       printf("       -U <file>   Update an already pinned BPF array\n");
+       printf("       -i <ifindex> Interface index\n");
+       printf("       -h          Display this help\n");
+}
+
+int main(int argc, char **argv)
+{
+       const char *pinned_file = NULL;
+       int ifindex = -1;
+       int array_key = 0;
+       int array_fd = -1;
+       int ret = -1;
+       int opt;
+
+       while ((opt = getopt(argc, argv, "F:U:i:")) != -1) {
+               switch (opt) {
+               /* General args */
+               case 'U':
+                       pinned_file = optarg;
+                       break;
+               case 'i':
+                       ifindex = atoi(optarg);
+                       break;
+               default:
+                       usage();
+                       goto out;
+               }
+       }
+
+       if (ifindex < 0 || !pinned_file) {
+               usage();
+               goto out;
+       }
+
+       array_fd = bpf_obj_get(pinned_file);
+       if (array_fd < 0) {
+               fprintf(stderr, "bpf_obj_get(%s): %s(%d)\n",
+                       pinned_file, strerror(errno), errno);
+               goto out;
+       }
+
+       /* bpf_tunnel_key.remote_ipv4 expects host byte orders */
+       ret = bpf_update_elem(array_fd, &array_key, &ifindex, 0);
+       if (ret) {
+               perror("bpf_update_elem");
+               goto out;
+       }
+
+out:
+       if (array_fd != -1)
+               close(array_fd);
+       return ret;
+}
index fa051b3d53ee0a8f18da0b0701e04d2962c3e4b6..274c884c87fe01f28adae47feecb9de7f4f0948e 100644 (file)
@@ -1,3 +1,4 @@
+#define KBUILD_MODNAME "foo"
 #include <uapi/linux/bpf.h>
 #include <uapi/linux/if_ether.h>
 #include <uapi/linux/if_packet.h>
index 3303bb85593bc62a21afcf4f2864869a40543b4d..9c823a609e75f8d66bbe1fa31a1ecebac7f65311 100644 (file)
@@ -5,6 +5,7 @@
  * modify it under the terms of version 2 of the GNU General Public
  * License as published by the Free Software Foundation.
  */
+#define KBUILD_MODNAME "foo"
 #include <uapi/linux/bpf.h>
 #include <uapi/linux/if_ether.h>
 #include <uapi/linux/if_packet.h>
index 10ff73404e3a80fe8bab464188335317ee71515a..1547b36a7b7b9bd5251dd1be6ae2a451cdca0a29 100644 (file)
@@ -4,6 +4,7 @@
  * modify it under the terms of version 2 of the GNU General Public
  * License as published by the Free Software Foundation.
  */
+#define KBUILD_MODNAME "foo"
 #include <uapi/linux/if_ether.h>
 #include <uapi/linux/in6.h>
 #include <uapi/linux/ipv6.h>
index 71a8ed32823ecc36cfc17b3ec519d611569dc7d6..41b6115a32eb1b0c06f13a0736690903e352839e 100644 (file)
@@ -50,7 +50,7 @@ int bpf_prog1(struct bpf_perf_event_data *ctx)
        key.userstack = bpf_get_stackid(ctx, &stackmap, USER_STACKID_FLAGS);
        if ((int)key.kernstack < 0 && (int)key.userstack < 0) {
                bpf_trace_printk(fmt, sizeof(fmt), cpu, ctx->sample_period,
-                                ctx->regs.ip);
+                                PT_REGS_IP(&ctx->regs));
                return 0;
        }
 
index de46ab03f063beaf980996102e0ec8911e173099..7675d11ee65e6d41e353debcd2fc51abff9a5dfa 100644 (file)
@@ -159,7 +159,8 @@ cmd_cpp_i_c       = $(CPP) $(c_flags) -o $@ $<
 $(obj)/%.i: $(src)/%.c FORCE
        $(call if_changed_dep,cpp_i_c)
 
-cmd_gensymtypes =                                                           \
+# These mirror gensymtypes_S and co below, keep them in synch.
+cmd_gensymtypes_c =                                                         \
     $(CPP) -D__GENKSYMS__ $(c_flags) $< |                                   \
     $(GENKSYMS) $(if $(1), -T $(2))                                         \
      $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))             \
@@ -169,7 +170,7 @@ cmd_gensymtypes =                                                           \
 quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
 cmd_cc_symtypes_c =                                                         \
     set -e;                                                                 \
-    $(call cmd_gensymtypes,true,$@) >/dev/null;                             \
+    $(call cmd_gensymtypes_c,true,$@) >/dev/null;                           \
     test -s $@ || rm -f $@
 
 $(obj)/%.symtypes : $(src)/%.c FORCE
@@ -198,9 +199,10 @@ else
 #   the actual value of the checksum generated by genksyms
 
 cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
-cmd_modversions =                                                              \
+
+cmd_modversions_c =                                                            \
        if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then             \
-               $(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes))    \
+               $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes))  \
                    > $(@D)/.tmp_$(@F:.o=.ver);                                 \
                                                                                \
                $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F)                      \
@@ -268,13 +270,14 @@ endif # CONFIG_STACK_VALIDATION
 define rule_cc_o_c
        $(call echo-cmd,checksrc) $(cmd_checksrc)                         \
        $(call cmd_and_fixdep,cc_o_c)                                     \
-       $(cmd_modversions)                                                \
+       $(cmd_modversions_c)                                              \
        $(cmd_objtool)                                                    \
        $(call echo-cmd,record_mcount) $(cmd_record_mcount)
 endef
 
 define rule_as_o_S
        $(call cmd_and_fixdep,as_o_S)                                     \
+       $(cmd_modversions_S)                                              \
        $(cmd_objtool)
 endef
 
@@ -314,6 +317,39 @@ modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)
 $(real-objs-m)      : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
 $(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
 
+# .S file exports must have their C prototypes defined in asm/asm-prototypes.h
+# or a file that it includes, in order to get versioned symbols. We build a
+# dummy C file that includes asm-prototypes and the EXPORT_SYMBOL lines from
+# the .S file (with trailing ';'), and run genksyms on that, to extract vers.
+#
+# This is convoluted. The .S file must first be preprocessed to run guards and
+# expand names, then the resulting exports must be constructed into plain
+# EXPORT_SYMBOL(symbol); to build our dummy C file, and that gets preprocessed
+# to make the genksyms input.
+#
+# These mirror gensymtypes_c and co above, keep them in synch.
+cmd_gensymtypes_S =                                                         \
+    (echo "\#include <linux/kernel.h>" ;                                    \
+     echo "\#include <asm/asm-prototypes.h>" ;                              \
+    $(CPP) $(a_flags) $< |                                                  \
+     grep "\<___EXPORT_SYMBOL\>" |                                          \
+     sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ) | \
+    $(CPP) -D__GENKSYMS__ $(c_flags) -xc - |                                \
+    $(GENKSYMS) $(if $(1), -T $(2))                                         \
+     $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))             \
+     $(if $(KBUILD_PRESERVE),-p)                                            \
+     -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
+
+quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@
+cmd_cc_symtypes_S =                                                         \
+    set -e;                                                                 \
+    $(call cmd_gensymtypes_S,true,$@) >/dev/null;                           \
+    test -s $@ || rm -f $@
+
+$(obj)/%.symtypes : $(src)/%.S FORCE
+       $(call cmd,cc_symtypes_S)
+
+
 quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@
 cmd_cpp_s_S       = $(CPP) $(a_flags) -o $@ $<
 
@@ -321,7 +357,37 @@ $(obj)/%.s: $(src)/%.S FORCE
        $(call if_changed_dep,cpp_s_S)
 
 quiet_cmd_as_o_S = AS $(quiet_modtag)  $@
-cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
+
+ifndef CONFIG_MODVERSIONS
+cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
+
+else
+
+ASM_PROTOTYPES := $(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/asm-prototypes.h)
+
+ifeq ($(ASM_PROTOTYPES),)
+cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
+
+else
+
+# versioning matches the C process described above, with difference that
+# we parse asm-prototypes.h C header to get function definitions.
+
+cmd_as_o_S = $(CC) $(a_flags) -c -o $(@D)/.tmp_$(@F) $<
+
+cmd_modversions_S =                                                            \
+       if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then             \
+               $(call cmd_gensymtypes_S,$(KBUILD_SYMTYPES),$(@:.o=.symtypes))  \
+                   > $(@D)/.tmp_$(@F:.o=.ver);                                 \
+                                                                               \
+               $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F)                      \
+                       -T $(@D)/.tmp_$(@F:.o=.ver);                            \
+               rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);                \
+       else                                                                    \
+               mv -f $(@D)/.tmp_$(@F) $@;                                      \
+       fi;
+endif
+endif
 
 $(obj)/%.o: $(src)/%.S $(objtool_obj) FORCE
        $(call if_changed_rule,as_o_S)
@@ -430,6 +496,9 @@ cmd_export_list = $(OBJDUMP) -h $< | \
 
 $(obj)/lib-ksyms.o: $(lib-target) FORCE
        $(call if_changed,export_list)
+
+targets += $(obj)/lib-ksyms.o
+
 endif
 
 #
index 53449a6ff6aa7de3c5c868f0645f6000b6f551e6..7c321a603b079d355bd127aebb04adc0294b4ba5 100644 (file)
@@ -36,6 +36,7 @@ warning-2 += -Wshadow
 warning-2 += $(call cc-option, -Wlogical-op)
 warning-2 += $(call cc-option, -Wmissing-field-initializers)
 warning-2 += $(call cc-option, -Wsign-compare)
+warning-2 += $(call cc-option, -Wmaybe-uninitialized)
 
 warning-3 := -Wbad-function-cast
 warning-3 += -Wcast-qual
index dd779c40c8e6af713c0ad7039bc929b0c6c2944a..3b1b13818d594f9ffa9dcb15206314ab349325a7 100644 (file)
@@ -17,4 +17,8 @@ endif
 ifdef CONFIG_UBSAN_NULL
       CFLAGS_UBSAN += $(call cc-option, -fsanitize=null)
 endif
+
+      # -fsanitize=* options makes GCC less smart than usual and
+      # increase number of 'maybe-uninitialized false-positives
+      CFLAGS_UBSAN += $(call cc-option, -Wno-maybe-uninitialized)
 endif
index 19f5adfd877dcf9b7e9c5b63c796ca72ee06dccf..d9ff038c1b28400799462dad5e29335b092b9a1a 100755 (executable)
@@ -8,6 +8,9 @@
 # of the GNU General Public License, incorporated herein by reference.
 
 import sys, os, re
+from signal import signal, SIGPIPE, SIG_DFL
+
+signal(SIGPIPE, SIG_DFL)
 
 if len(sys.argv) != 3:
     sys.stderr.write("usage: %s file1 file2\n" % sys.argv[0])
index 34df974c6ba3a586435dc0ce313a3986d0031d6c..8af7db06122d21b91667755767d0967824b05694 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "gcc-common.h"
 
-int plugin_is_GPL_compatible;
+__visible int plugin_is_GPL_compatible;
 
 static struct plugin_info cyc_complexity_plugin_info = {
        .version        = "20160225",
@@ -49,7 +49,7 @@ static unsigned int cyc_complexity_execute(void)
 
 #include "gcc-generate-gimple-pass.h"
 
-int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
 {
        const char * const plugin_name = plugin_info->base_name;
        struct register_pass_info cyc_complexity_pass_info;
index 172850bcd0d9f0eefe6b575f6417ed2397889ccf..950fd2e64bb73b9f261188bba272ea7e7ec10249 100644 (file)
@@ -130,6 +130,7 @@ extern void dump_gimple_stmt(pretty_printer *, gimple, int, int);
 #endif
 
 #define __unused __attribute__((__unused__))
+#define __visible __attribute__((visibility("default")))
 
 #define DECL_NAME_POINTER(node) IDENTIFIER_POINTER(DECL_NAME(node))
 #define DECL_NAME_LENGTH(node) IDENTIFIER_LENGTH(DECL_NAME(node))
index ff1939b804aefe75631431b45e6f7ce80cc133f3..8160f1c1b56ed941a6e15f7c906f8fb990edcdd3 100644 (file)
@@ -77,7 +77,7 @@
 
 #include "gcc-common.h"
 
-int plugin_is_GPL_compatible;
+__visible int plugin_is_GPL_compatible;
 
 static GTY(()) tree latent_entropy_decl;
 
@@ -340,7 +340,7 @@ static enum tree_code get_op(tree *rhs)
                break;
        }
        if (rhs)
-               *rhs = build_int_cstu(unsigned_intDI_type_node, random_const);
+               *rhs = build_int_cstu(long_unsigned_type_node, random_const);
        return op;
 }
 
@@ -372,7 +372,7 @@ static void __perturb_latent_entropy(gimple_stmt_iterator *gsi,
        enum tree_code op;
 
        /* 1. create temporary copy of latent_entropy */
-       temp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy");
+       temp = create_var(long_unsigned_type_node, "temp_latent_entropy");
 
        /* 2. read... */
        add_referenced_var(latent_entropy_decl);
@@ -459,13 +459,13 @@ static void init_local_entropy(basic_block bb, tree local_entropy)
        gsi_insert_before(&gsi, call, GSI_NEW_STMT);
        update_stmt(call);
 
-       udi_frame_addr = fold_convert(unsigned_intDI_type_node, frame_addr);
+       udi_frame_addr = fold_convert(long_unsigned_type_node, frame_addr);
        assign = gimple_build_assign(local_entropy, udi_frame_addr);
        gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
        update_stmt(assign);
 
        /* 3. create temporary copy of latent_entropy */
-       tmp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy");
+       tmp = create_var(long_unsigned_type_node, "temp_latent_entropy");
 
        /* 4. read the global entropy variable into local entropy */
        add_referenced_var(latent_entropy_decl);
@@ -480,7 +480,7 @@ static void init_local_entropy(basic_block bb, tree local_entropy)
        update_stmt(assign);
 
        rand_cst = get_random_const();
-       rand_const = build_int_cstu(unsigned_intDI_type_node, rand_cst);
+       rand_const = build_int_cstu(long_unsigned_type_node, rand_cst);
        op = get_op(NULL);
        assign = create_assign(op, local_entropy, local_entropy, rand_const);
        gsi_insert_after(&gsi, assign, GSI_NEW_STMT);
@@ -529,7 +529,7 @@ static unsigned int latent_entropy_execute(void)
        }
 
        /* 1. create the local entropy variable */
-       local_entropy = create_var(unsigned_intDI_type_node, "local_entropy");
+       local_entropy = create_var(long_unsigned_type_node, "local_entropy");
 
        /* 2. initialize the local entropy variable */
        init_local_entropy(bb, local_entropy);
@@ -561,10 +561,9 @@ static void latent_entropy_start_unit(void *gcc_data __unused,
        if (in_lto_p)
                return;
 
-       /* extern volatile u64 latent_entropy */
-       gcc_assert(TYPE_PRECISION(long_long_unsigned_type_node) == 64);
-       quals = TYPE_QUALS(long_long_unsigned_type_node) | TYPE_QUAL_VOLATILE;
-       type = build_qualified_type(long_long_unsigned_type_node, quals);
+       /* extern volatile unsigned long latent_entropy */
+       quals = TYPE_QUALS(long_unsigned_type_node) | TYPE_QUAL_VOLATILE;
+       type = build_qualified_type(long_unsigned_type_node, quals);
        id = get_identifier("latent_entropy");
        latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type);
 
@@ -584,8 +583,8 @@ static void latent_entropy_start_unit(void *gcc_data __unused,
        | TODO_update_ssa
 #include "gcc-generate-gimple-pass.h"
 
-int plugin_init(struct plugin_name_args *plugin_info,
-               struct plugin_gcc_version *version)
+__visible int plugin_init(struct plugin_name_args *plugin_info,
+                         struct plugin_gcc_version *version)
 {
        bool enabled = true;
        const char * const plugin_name = plugin_info->base_name;
index aedd6113cb731bcbbec89620e1e4fb4512cef4b2..7ea0b3f50739e319a8ec57de40654d241e5a78f7 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "gcc-common.h"
 
-int plugin_is_GPL_compatible;
+__visible int plugin_is_GPL_compatible;
 
 tree sancov_fndecl;
 
@@ -86,7 +86,7 @@ static void sancov_start_unit(void __unused *gcc_data, void __unused *user_data)
 #endif
 }
 
-int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
 {
        int i;
        struct register_pass_info sancov_plugin_pass_info;
index 973e8c1415677eeba513543655e939de234521e3..17867e723a51a667fdec65194b9033346ff1b786 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
+echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fno-PIE -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
 if [ "$?" -eq "0" ] ; then
        echo y
 else
index ebced77deb9c4dc380ab5f58751950adc0ac3d7f..90a091b6ae4de74e6c070d77255b9f4b5655629a 100644 (file)
@@ -35,6 +35,8 @@ nconfig: $(obj)/nconf
 
 silentoldconfig: $(obj)/conf
        $(Q)mkdir -p include/config include/generated
+       $(Q)test -e include/generated/autoksyms.h || \
+           touch   include/generated/autoksyms.h
        $< $(silent) --$@ $(Kconfig)
 
 localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
index fc3036b34e5128cc73910eb6e3b2bbd2d94d9e50..a4d90aa1045afc46499e00da9baf9bbcea34752a 100644 (file)
@@ -621,8 +621,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
        /* released below */
        cred = get_current_cred();
        cxt = cred_cxt(cred);
-       profile = aa_cred_profile(cred);
-       previous_profile = cxt->previous;
+       profile = aa_get_newest_profile(aa_cred_profile(cred));
+       previous_profile = aa_get_newest_profile(cxt->previous);
 
        if (unconfined(profile)) {
                info = "unconfined";
@@ -718,6 +718,8 @@ audit:
 out:
        aa_put_profile(hat);
        kfree(name);
+       aa_put_profile(profile);
+       aa_put_profile(previous_profile);
        put_cred(cred);
 
        return error;
index f826e87390233c1cfddb87e969642ab44219d84f..d942c7c2bc0aa0ee471de663d3f15587f12a1732 100644 (file)
@@ -41,7 +41,7 @@ config BIG_KEYS
        bool "Large payload keys"
        depends on KEYS
        depends on TMPFS
-       select CRYPTO
+       depends on (CRYPTO_ANSI_CPRNG = y || CRYPTO_DRBG = y)
        select CRYPTO_AES
        select CRYPTO_ECB
        select CRYPTO_RNG
index c0b3030b563486af0f1756d6d73ae32fe02a77c8..835c1ab30d01eb9a8e94b411fce09b856772efb9 100644 (file)
@@ -9,6 +9,7 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) "big_key: "fmt
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/file.h>
@@ -341,44 +342,48 @@ error:
  */
 static int __init big_key_init(void)
 {
-       return register_key_type(&key_type_big_key);
-}
-
-/*
- * Initialize big_key crypto and RNG algorithms
- */
-static int __init big_key_crypto_init(void)
-{
-       int ret = -EINVAL;
+       struct crypto_skcipher *cipher;
+       struct crypto_rng *rng;
+       int ret;
 
-       /* init RNG */
-       big_key_rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
-       if (IS_ERR(big_key_rng)) {
-               big_key_rng = NULL;
-               return -EFAULT;
+       rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
+       if (IS_ERR(rng)) {
+               pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng));
+               return PTR_ERR(rng);
        }
 
+       big_key_rng = rng;
+
        /* seed RNG */
-       ret = crypto_rng_reset(big_key_rng, NULL, crypto_rng_seedsize(big_key_rng));
-       if (ret)
-               goto error;
+       ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
+       if (ret) {
+               pr_err("Can't reset rng: %d\n", ret);
+               goto error_rng;
+       }
 
        /* init block cipher */
-       big_key_skcipher = crypto_alloc_skcipher(big_key_alg_name,
-                                                0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(big_key_skcipher)) {
-               big_key_skcipher = NULL;
-               ret = -EFAULT;
-               goto error;
+       cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(cipher)) {
+               ret = PTR_ERR(cipher);
+               pr_err("Can't alloc crypto: %d\n", ret);
+               goto error_rng;
+       }
+
+       big_key_skcipher = cipher;
+
+       ret = register_key_type(&key_type_big_key);
+       if (ret < 0) {
+               pr_err("Can't register type: %d\n", ret);
+               goto error_cipher;
        }
 
        return 0;
 
-error:
+error_cipher:
+       crypto_free_skcipher(big_key_skcipher);
+error_rng:
        crypto_free_rng(big_key_rng);
-       big_key_rng = NULL;
        return ret;
 }
 
-device_initcall(big_key_init);
-late_initcall(big_key_crypto_init);
+late_initcall(big_key_init);
index f0611a6368cd2572188f9a066291b9c8d717f95d..b9f531c9e4fa753d326752b63dc2cf599579ffeb 100644 (file)
@@ -181,7 +181,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
        struct timespec now;
        unsigned long timo;
        key_ref_t key_ref, skey_ref;
-       char xbuf[12];
+       char xbuf[16];
        int rc;
 
        struct keyring_search_context ctx = {
index 085057936287bdaa559e7c4be9e593e17ec1dfa9..09fd6108e42134871953f2cb46f9410808c1f702 100644 (file)
@@ -3557,7 +3557,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                } else if (!vma->vm_file &&
                           ((vma->vm_start <= vma->vm_mm->start_stack &&
                             vma->vm_end >= vma->vm_mm->start_stack) ||
-                           vma_is_stack_for_task(vma, current))) {
+                           vma_is_stack_for_current(vma))) {
                        rc = current_has_perm(current, PROCESS__EXECSTACK);
                } else if (vma->vm_file && vma->anon_vma) {
                        /*
index ade7c6cad172a13833a3b41799a142ebf4cb4f46..682b73af77661a4c6260b9f450e015d86c453ede 100644 (file)
@@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
         * the execve().
         */
        if (get_user_pages_remote(current, bprm->mm, pos, 1,
-                               0, 1, &page, NULL) <= 0)
+                               FOLL_FORCE, &page, NULL) <= 0)
                return false;
 #else
        page = bprm->page[pos / PAGE_SIZE];
index 895362a696c95b3737bf82123cba9b00146bb6a6..8ab72e0f593292ac91aea0b06b70d89fc084bd3c 100644 (file)
@@ -325,10 +325,15 @@ static ssize_t snd_info_text_entry_write(struct file *file,
        size_t next;
        int err = 0;
 
+       if (!entry->c.text.write)
+               return -EIO;
        pos = *offset;
        if (!valid_pos(pos, count))
                return -EIO;
        next = pos + count;
+       /* don't handle too large text inputs */
+       if (next > 16 * 1024)
+               return -EIO;
        mutex_lock(&entry->access);
        buf = data->wbuffer;
        if (!buf) {
@@ -366,7 +371,9 @@ static int snd_info_seq_show(struct seq_file *seq, void *p)
        struct snd_info_private_data *data = seq->private;
        struct snd_info_entry *entry = data->entry;
 
-       if (entry->c.text.read) {
+       if (!entry->c.text.read) {
+               return -EIO;
+       } else {
                data->rbuffer->buffer = (char *)seq; /* XXX hack! */
                entry->c.text.read(entry, data->rbuffer);
        }
index dcc102813aefa4d1d6e30e24f8644c8d92b12a9f..37d9cfbc29f9c829facd29ffdc2224ada7a63efd 100644 (file)
@@ -448,8 +448,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
 
                ktime_get_ts64(&tm);
                tm = timespec64_sub(tm, tmr->last_update);
-               cur_time.tv_nsec = tm.tv_nsec;
-               cur_time.tv_sec = tm.tv_sec;
+               cur_time.tv_nsec += tm.tv_nsec;
+               cur_time.tv_sec += tm.tv_sec;
                snd_seq_sanity_real_time(&cur_time);
        }
        spin_unlock_irqrestore(&tmr->lock, flags);
index d17937b92331e4c1160d1cebb1ed77398a684a01..7e3aa50b21f9d2d2f5ca49f3f9a779ab1276ee4a 100644 (file)
@@ -111,7 +111,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return -EINVAL;
 
        hm = kmalloc(sizeof(*hm), GFP_KERNEL);
-       hr = kmalloc(sizeof(*hr), GFP_KERNEL);
+       hr = kzalloc(sizeof(*hr), GFP_KERNEL);
        if (!hm || !hr) {
                err = -ENOMEM;
                goto out;
index c3469f756ec258cccba7f1a339a4335d318bcc23..c64d986009a9ecf5233464d269a440a0edb6cf23 100644 (file)
@@ -341,8 +341,7 @@ enum {
 
 /* quirks for Nvidia */
 #define AZX_DCAPS_PRESET_NVIDIA \
-       (AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \
-        AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\
+       (AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\
         AZX_DCAPS_SNOOP_TYPE(NVIDIA))
 
 #define AZX_DCAPS_PRESET_CTHDA \
@@ -1716,6 +1715,10 @@ static int azx_first_init(struct azx *chip)
                }
        }
 
+       /* NVidia hardware normally only supports up to 40 bits of DMA */
+       if (chip->pci->vendor == PCI_VENDOR_ID_NVIDIA)
+               dma_bits = 40;
+
        /* disable 64bit DMA address on some devices */
        if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
                dev_dbg(card->dev, "Disabling 64bit DMA\n");
index b58e8c76346ac9e87bd208b88ae8882546fa78c1..ea81c08ddc7acf77dc7c4144a5b093b0d72ef867 100644 (file)
@@ -5811,8 +5811,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
 #define ALC295_STANDARD_PINS \
        {0x12, 0xb7a60130}, \
        {0x14, 0x90170110}, \
-       {0x17, 0x21014020}, \
-       {0x18, 0x21a19030}, \
        {0x21, 0x04211020}
 
 #define ALC298_STANDARD_PINS \
@@ -5858,10 +5856,18 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x14, 0x90170110},
                {0x1b, 0x02011020},
                {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x1b, 0x01011020},
+               {0x21, 0x0221101f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x14, 0x90170130},
                {0x1b, 0x01014020},
                {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170130},
+               {0x1b, 0x01011020},
+               {0x21, 0x0221103f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x14, 0x90170130},
                {0x1b, 0x02011020},
@@ -6039,7 +6045,13 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                ALC292_STANDARD_PINS,
                {0x13, 0x90a60140}),
        SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC295_STANDARD_PINS),
+               ALC295_STANDARD_PINS,
+               {0x17, 0x21014020},
+               {0x18, 0x21a19030}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC295_STANDARD_PINS,
+               {0x17, 0x21014040},
+               {0x18, 0x21a19050}),
        SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC298_STANDARD_PINS,
                {0x17, 0x90170110}),
@@ -6613,6 +6625,7 @@ enum {
        ALC891_FIXUP_HEADSET_MODE,
        ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
        ALC662_FIXUP_ACER_VERITON,
+       ALC892_FIXUP_ASROCK_MOBO,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -6889,6 +6902,14 @@ static const struct hda_fixup alc662_fixups[] = {
                        { }
                }
        },
+       [ALC892_FIXUP_ASROCK_MOBO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x40f000f0 }, /* disabled */
+                       { 0x16, 0x40f000f0 }, /* disabled */
+                       { }
+               }
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -6926,6 +6947,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+       SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
        SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
        SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
        SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
index 6a23302297c9cc4b74fd66eab52a32433a45949c..4d9d320a79711f5e95deac5f32c2ac0f741ff21d 100644 (file)
@@ -13,7 +13,8 @@ static void (*old_vmaster_hook)(void *, int);
 static bool is_thinkpad(struct hda_codec *codec)
 {
        return (codec->core.subsystem_id >> 16 == 0x17aa) &&
-              (acpi_dev_found("LEN0068") || acpi_dev_found("IBM0068"));
+              (acpi_dev_found("LEN0068") || acpi_dev_found("LEN0268") ||
+               acpi_dev_found("IBM0068"));
 }
 
 static void update_tpacpi_mute_led(void *private_data, int enabled)
index 22aec9a1e9a4991026e98b40879e2064997b92a1..4a56f3dfba5132a01bbb49eb985540d16a944ecf 100644 (file)
@@ -78,4 +78,14 @@ config SND_ATMEL_SOC_PDMIC
        help
          Say Y if you want to add support for Atmel ASoC driver for boards using
          PDMIC.
+
+config SND_ATMEL_SOC_TSE850_PCM5142
+       tristate "ASoC driver for the Axentia TSE-850"
+       depends on ARCH_AT91 && OF
+       depends on ATMEL_SSC && I2C
+       select SND_ATMEL_SOC_SSC_DMA
+       select SND_SOC_PCM512x_I2C
+       help
+         Say Y if you want to add support for the ASoC driver for the
+         Axentia TSE-850 with a PCM5142 codec.
 endif
index a2b127bd9c8717ac6c1501eff669014c306058a5..67e10cbd4ed70a39c536371f3be977022a5673e0 100644 (file)
@@ -13,9 +13,11 @@ snd-atmel-soc-wm8904-objs := atmel_wm8904.o
 snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
 snd-atmel-soc-classd-objs := atmel-classd.o
 snd-atmel-soc-pdmic-objs := atmel-pdmic.o
+snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
 obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
+obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
index 16e459aedffe4c3a4af7733b9ea6cf22087c7fa2..a1e2c5682dcda82b5c04566f6d773659dcc4bb47 100644 (file)
@@ -380,6 +380,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
                ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
                /* Clear the SSC dividers */
                ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
+               ssc_p->forced_divider = 0;
        }
        spin_unlock_irq(&ssc_p->lock);
 
@@ -426,14 +427,17 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
                else
                        if (div != ssc_p->cmr_div)
                                return -EBUSY;
+               ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV);
                break;
 
        case ATMEL_SSC_TCMR_PERIOD:
                ssc_p->tcmr_period = div;
+               ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD);
                break;
 
        case ATMEL_SSC_RCMR_PERIOD:
                ssc_p->rcmr_period = div;
+               ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD);
                break;
 
        default:
@@ -443,6 +447,28 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
+/* Is the cpu-dai master of the frame clock? */
+static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)
+{
+       switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBS_CFS:
+               return 1;
+       }
+       return 0;
+}
+
+/* Is the cpu-dai master of the bit clock? */
+static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p)
+{
+       switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_CBS_CFS:
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * Configure the SSC.
  */
@@ -459,6 +485,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        u32 tfmr, rfmr, tcmr, rcmr;
        int ret;
        int fslen, fslen_ext;
+       u32 cmr_div;
+       u32 tcmr_period;
+       u32 rcmr_period;
 
        /*
         * Currently, there is only one set of dma params for
@@ -470,6 +499,46 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        else
                dir = 1;
 
+       /*
+        * If the cpu dai should provide BCLK, but noone has provided the
+        * divider needed for that to work, fall back to something sensible.
+        */
+       cmr_div = ssc_p->cmr_div;
+       if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) &&
+           atmel_ssc_cbs(ssc_p)) {
+               int bclk_rate = snd_soc_params_to_bclk(params);
+
+               if (bclk_rate < 0) {
+                       dev_err(dai->dev, "unable to calculate cmr_div: %d\n",
+                               bclk_rate);
+                       return bclk_rate;
+               }
+
+               cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate);
+       }
+
+       /*
+        * If the cpu dai should provide LRCLK, but noone has provided the
+        * dividers needed for that to work, fall back to something sensible.
+        */
+       tcmr_period = ssc_p->tcmr_period;
+       rcmr_period = ssc_p->rcmr_period;
+       if (atmel_ssc_cfs(ssc_p)) {
+               int frame_size = snd_soc_params_to_frame_size(params);
+
+               if (frame_size < 0) {
+                       dev_err(dai->dev,
+                               "unable to calculate tx/rx cmr_period: %d\n",
+                               frame_size);
+                       return frame_size;
+               }
+
+               if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD)))
+                       tcmr_period = frame_size / 2 - 1;
+               if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD)))
+                       rcmr_period = frame_size / 2 - 1;
+       }
+
        dma_params = ssc_p->dma_params[dir];
 
        channels = params_channels(params);
@@ -524,7 +593,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                fslen_ext = (bits - 1) / 16;
                fslen = (bits - 1) % 16;
 
-               rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+               rcmr =    SSC_BF(RCMR_PERIOD, rcmr_period)
                        | SSC_BF(RCMR_STTDLY, START_DELAY)
                        | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
                        | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
@@ -540,7 +609,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(RFMR_LOOP, 0)
                        | SSC_BF(RFMR_DATLEN, (bits - 1));
 
-               tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+               tcmr =    SSC_BF(TCMR_PERIOD, tcmr_period)
                        | SSC_BF(TCMR_STTDLY, START_DELAY)
                        | SSC_BF(TCMR_START, SSC_START_FALLING_RF)
                        | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
@@ -606,7 +675,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                fslen_ext = (bits - 1) / 16;
                fslen = (bits - 1) % 16;
 
-               rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+               rcmr =    SSC_BF(RCMR_PERIOD, rcmr_period)
                        | SSC_BF(RCMR_STTDLY, START_DELAY)
                        | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
                        | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
@@ -623,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(RFMR_LOOP, 0)
                        | SSC_BF(RFMR_DATLEN, (bits - 1));
 
-               tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+               tcmr =    SSC_BF(TCMR_PERIOD, tcmr_period)
                        | SSC_BF(TCMR_STTDLY, START_DELAY)
                        | SSC_BF(TCMR_START, SSC_START_FALLING_RF)
                        | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
@@ -650,7 +719,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                 * MCK divider, and the BCLK signal is output
                 * on the SSC TK line.
                 */
-               rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+               rcmr =    SSC_BF(RCMR_PERIOD, rcmr_period)
                        | SSC_BF(RCMR_STTDLY, 1)
                        | SSC_BF(RCMR_START, SSC_START_RISING_RF)
                        | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
@@ -665,7 +734,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(RFMR_LOOP, 0)
                        | SSC_BF(RFMR_DATLEN, (bits - 1));
 
-               tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+               tcmr =    SSC_BF(TCMR_PERIOD, tcmr_period)
                        | SSC_BF(TCMR_STTDLY, 1)
                        | SSC_BF(TCMR_START, SSC_START_RISING_RF)
                        | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
@@ -760,7 +829,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* set SSC clock mode register */
-       ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
+       ssc_writel(ssc_p->ssc->regs, CMR, cmr_div);
 
        /* set receive clock mode and format */
        ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
index 80b153857a88ac25e86d3c4df1fc6ad45f108dc7..75194f5821317411d323c918b1db5cfab9d38f47 100644 (file)
@@ -113,6 +113,7 @@ struct atmel_ssc_info {
        unsigned short cmr_div;
        unsigned short tcmr_period;
        unsigned short rcmr_period;
+       unsigned int forced_divider;
        struct atmel_pcm_dma_params *dma_params[2];
        struct atmel_ssc_state ssc_state;
        unsigned long mck_rate;
index fdd28ed3e0b9ec3d6c80e7081dd03b408472f45b..fbc10f61eb553dfeb2d2d5bcdc98960bc75f1c3b 100644 (file)
@@ -53,7 +53,7 @@ static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_ops atmel_asoc_wm8904_ops = {
+static const struct snd_soc_ops atmel_asoc_wm8904_ops = {
        .hw_params = atmel_asoc_wm8904_hw_params,
 };
 
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
new file mode 100644 (file)
index 0000000..ac6a814
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec
+ *
+ * Copyright (C) 2016 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * 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.
+ */
+
+/*
+ *               loop1 relays
+ *   IN1 +---o  +------------+  o---+ OUT1
+ *            \                /
+ *             +              +
+ *             |   /          |
+ *             +--o  +--.     |
+ *             |  add   |     |
+ *             |        V     |
+ *             |      .---.   |
+ *   DAC +----------->|Sum|---+
+ *             |      '---'   |
+ *             |              |
+ *             +              +
+ *
+ *   IN2 +---o--+------------+--o---+ OUT2
+ *               loop2 relays
+ *
+ * The 'loop1' gpio pin controlls two relays, which are either in loop
+ * position, meaning that input and output are directly connected, or
+ * they are in mixer position, meaning that the signal is passed through
+ * the 'Sum' mixer. Similarly for 'loop2'.
+ *
+ * In the above, the 'loop1' relays are inactive, thus feeding IN1 to the
+ * mixer (if 'add' is active) and feeding the mixer output to OUT1. The
+ * 'loop2' relays are active, short-cutting the TSE-850 from channel 2.
+ * IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name
+ * of the (filtered) output from the PCM5142 codec.
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include "atmel_ssc_dai.h"
+
+struct tse850_priv {
+       int ssc_id;
+
+       struct gpio_desc *add;
+       struct gpio_desc *loop1;
+       struct gpio_desc *loop2;
+
+       struct regulator *ana;
+
+       int add_cache;
+       int loop1_cache;
+       int loop2_cache;
+};
+
+static int tse850_get_mux1(struct snd_kcontrol *kctrl,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+
+       ucontrol->value.enumerated.item[0] = tse850->loop1_cache;
+
+       return 0;
+}
+
+static int tse850_put_mux1(struct snd_kcontrol *kctrl,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+       struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
+       unsigned int val = ucontrol->value.enumerated.item[0];
+
+       if (val >= e->items)
+               return -EINVAL;
+
+       gpiod_set_value_cansleep(tse850->loop1, val);
+       tse850->loop1_cache = val;
+
+       return snd_soc_dapm_put_enum_double(kctrl, ucontrol);
+}
+
+static int tse850_get_mux2(struct snd_kcontrol *kctrl,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+
+       ucontrol->value.enumerated.item[0] = tse850->loop2_cache;
+
+       return 0;
+}
+
+static int tse850_put_mux2(struct snd_kcontrol *kctrl,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+       struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
+       unsigned int val = ucontrol->value.enumerated.item[0];
+
+       if (val >= e->items)
+               return -EINVAL;
+
+       gpiod_set_value_cansleep(tse850->loop2, val);
+       tse850->loop2_cache = val;
+
+       return snd_soc_dapm_put_enum_double(kctrl, ucontrol);
+}
+
+int tse850_get_mix(struct snd_kcontrol *kctrl,
+                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+
+       ucontrol->value.enumerated.item[0] = tse850->add_cache;
+
+       return 0;
+}
+
+int tse850_put_mix(struct snd_kcontrol *kctrl,
+                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+       int connect = !!ucontrol->value.integer.value[0];
+
+       if (tse850->add_cache == connect)
+               return 0;
+
+       /*
+        * Hmmm, this gpiod_set_value_cansleep call should probably happen
+        * inside snd_soc_dapm_mixer_update_power in the loop.
+        */
+       gpiod_set_value_cansleep(tse850->add, connect);
+       tse850->add_cache = connect;
+
+       snd_soc_dapm_mixer_update_power(dapm, kctrl, connect, NULL);
+       return 1;
+}
+
+int tse850_get_ana(struct snd_kcontrol *kctrl,
+                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       ret = regulator_get_voltage(tse850->ana);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Map regulator output values like so:
+        *      -11.5V to "Low" (enum 0)
+        * 11.5V-12.5V to "12V" (enum 1)
+        * 12.5V-13.5V to "13V" (enum 2)
+        *     ...
+        * 18.5V-19.5V to "19V" (enum 8)
+        * 19.5V-      to "20V" (enum 9)
+        */
+       if (ret < 11000000)
+               ret = 11000000;
+       else if (ret > 20000000)
+               ret = 20000000;
+       ret -= 11000000;
+       ret = (ret + 500000) / 1000000;
+
+       ucontrol->value.enumerated.item[0] = ret;
+
+       return 0;
+}
+
+int tse850_put_ana(struct snd_kcontrol *kctrl,
+                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
+       struct snd_soc_card *card = dapm->card;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+       struct soc_enum *e = (struct soc_enum *)kctrl->private_value;
+       unsigned int uV = ucontrol->value.enumerated.item[0];
+       int ret;
+
+       if (uV >= e->items)
+               return -EINVAL;
+
+       /*
+        * Map enum zero (Low) to 2 volts on the regulator, do this since
+        * the ana regulator is supplied by the system 12V voltage and
+        * requesting anything below the system voltage causes the system
+        * voltage to be passed through the regulator. Also, the ana
+        * regulator induces noise when requesting voltages near the
+        * system voltage. So, by mapping Low to 2V, that noise is
+        * eliminated when all that is needed is 12V (the system voltage).
+        */
+       if (uV)
+               uV = 11000000 + (1000000 * uV);
+       else
+               uV = 2000000;
+
+       ret = regulator_set_voltage(tse850->ana, uV, uV);
+       if (ret < 0)
+               return ret;
+
+       return snd_soc_dapm_put_enum_double(kctrl, ucontrol);
+}
+
+static const char * const mux_text[] = { "Mixer", "Loop" };
+
+static const struct soc_enum mux_enum =
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, mux_text);
+
+static const struct snd_kcontrol_new mux1 =
+       SOC_DAPM_ENUM_EXT("MUX1", mux_enum, tse850_get_mux1, tse850_put_mux1);
+
+static const struct snd_kcontrol_new mux2 =
+       SOC_DAPM_ENUM_EXT("MUX2", mux_enum, tse850_get_mux2, tse850_put_mux2);
+
+#define TSE850_DAPM_SINGLE_EXT(xname, reg, shift, max, invert, xget, xput) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = xget, \
+       .put = xput, \
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+
+static const struct snd_kcontrol_new mix[] = {
+       TSE850_DAPM_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0,
+                              tse850_get_mix, tse850_put_mix),
+};
+
+static const char * const ana_text[] = {
+       "Low", "12V", "13V", "14V", "15V", "16V", "17V", "18V", "19V", "20V"
+};
+
+static const struct soc_enum ana_enum =
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 9, ana_text);
+
+static const struct snd_kcontrol_new out =
+       SOC_DAPM_ENUM_EXT("ANA", ana_enum, tse850_get_ana, tse850_put_ana);
+
+static const struct snd_soc_dapm_widget tse850_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("OUT1", NULL),
+       SND_SOC_DAPM_LINE("OUT2", NULL),
+       SND_SOC_DAPM_LINE("IN1", NULL),
+       SND_SOC_DAPM_LINE("IN2", NULL),
+       SND_SOC_DAPM_INPUT("DAC"),
+       SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+       SOC_MIXER_ARRAY("MIX", SND_SOC_NOPM, 0, 0, mix),
+       SND_SOC_DAPM_MUX("MUX1", SND_SOC_NOPM, 0, 0, &mux1),
+       SND_SOC_DAPM_MUX("MUX2", SND_SOC_NOPM, 0, 0, &mux2),
+       SND_SOC_DAPM_OUT_DRV("OUT", SND_SOC_NOPM, 0, 0, &out, 1),
+};
+
+/*
+ * These connections are not entirely correct, since both IN1 and IN2
+ * are always fed to MIX (if the "IN switch" is set so), i.e. without
+ * regard to the loop1 and loop2 relays that according to this only
+ * control MUX1 and MUX2 but in fact also control how the input signals
+ * are routed.
+ * But, 1) I don't know how to do it right, and 2) it doesn't seem to
+ * matter in practice since nothing is powered in those sections anyway.
+ */
+static const struct snd_soc_dapm_route tse850_intercon[] = {
+       { "OUT1", NULL, "MUX1" },
+       { "OUT2", NULL, "MUX2" },
+
+       { "MUX1", "Loop",  "IN1" },
+       { "MUX1", "Mixer", "OUT" },
+
+       { "MUX2", "Loop",  "IN2" },
+       { "MUX2", "Mixer", "OUT" },
+
+       { "OUT", NULL, "MIX" },
+
+       { "MIX", NULL, "DAC" },
+       { "MIX", "IN Switch", "IN1" },
+       { "MIX", "IN Switch", "IN2" },
+
+       /* connect board input to the codec left channel output pin */
+       { "DAC", NULL, "OUTL" },
+};
+
+static struct snd_soc_dai_link tse850_dailink = {
+       .name = "TSE-850",
+       .stream_name = "TSE-850-PCM",
+       .codec_dai_name = "pcm512x-hifi",
+       .dai_fmt = SND_SOC_DAIFMT_I2S
+                | SND_SOC_DAIFMT_NB_NF
+                | SND_SOC_DAIFMT_CBM_CFS,
+};
+
+static struct snd_soc_card tse850_card = {
+       .name = "TSE-850-ASoC",
+       .owner = THIS_MODULE,
+       .dai_link = &tse850_dailink,
+       .num_links = 1,
+       .dapm_widgets = tse850_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tse850_dapm_widgets),
+       .dapm_routes = tse850_intercon,
+       .num_dapm_routes = ARRAY_SIZE(tse850_intercon),
+       .fully_routed = true,
+};
+
+static int tse850_dt_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *codec_np, *cpu_np;
+       struct snd_soc_card *card = &tse850_card;
+       struct snd_soc_dai_link *dailink = &tse850_dailink;
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+
+       if (!np) {
+               dev_err(&pdev->dev, "only device tree supported\n");
+               return -EINVAL;
+       }
+
+       cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "failed to get dai and pcm info\n");
+               return -EINVAL;
+       }
+       dailink->cpu_of_node = cpu_np;
+       dailink->platform_of_node = cpu_np;
+       tse850->ssc_id = of_alias_get_id(cpu_np, "ssc");
+       of_node_put(cpu_np);
+
+       codec_np = of_parse_phandle(np, "axentia,audio-codec", 0);
+       if (!codec_np) {
+               dev_err(&pdev->dev, "failed to get codec info\n");
+               return -EINVAL;
+       }
+       dailink->codec_of_node = codec_np;
+       of_node_put(codec_np);
+
+       return 0;
+}
+
+static int tse850_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &tse850_card;
+       struct device *dev = card->dev = &pdev->dev;
+       struct tse850_priv *tse850;
+       int ret;
+
+       tse850 = devm_kzalloc(dev, sizeof(*tse850), GFP_KERNEL);
+       if (!tse850)
+               return -ENOMEM;
+
+       snd_soc_card_set_drvdata(card, tse850);
+
+       ret = tse850_dt_init(pdev);
+       if (ret) {
+               dev_err(dev, "failed to init dt info\n");
+               return ret;
+       }
+
+       tse850->add = devm_gpiod_get(dev, "axentia,add", GPIOD_OUT_HIGH);
+       if (IS_ERR(tse850->add)) {
+               if (PTR_ERR(tse850->add) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get 'add' gpio\n");
+               return PTR_ERR(tse850->add);
+       }
+       tse850->add_cache = 1;
+
+       tse850->loop1 = devm_gpiod_get(dev, "axentia,loop1", GPIOD_OUT_HIGH);
+       if (IS_ERR(tse850->loop1)) {
+               if (PTR_ERR(tse850->loop1) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get 'loop1' gpio\n");
+               return PTR_ERR(tse850->loop1);
+       }
+       tse850->loop1_cache = 1;
+
+       tse850->loop2 = devm_gpiod_get(dev, "axentia,loop2", GPIOD_OUT_HIGH);
+       if (IS_ERR(tse850->loop2)) {
+               if (PTR_ERR(tse850->loop2) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get 'loop2' gpio\n");
+               return PTR_ERR(tse850->loop2);
+       }
+       tse850->loop2_cache = 1;
+
+       tse850->ana = devm_regulator_get(dev, "axentia,ana");
+       if (IS_ERR(tse850->ana)) {
+               if (PTR_ERR(tse850->ana) != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get 'ana' regulator\n");
+               return PTR_ERR(tse850->ana);
+       }
+
+       ret = regulator_enable(tse850->ana);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable the 'ana' regulator\n");
+               return ret;
+       }
+
+       ret = atmel_ssc_set_audio(tse850->ssc_id);
+       if (ret != 0) {
+               dev_err(dev,
+                       "failed to set SSC %d for audio\n", tse850->ssc_id);
+               goto err_disable_ana;
+       }
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(dev, "snd_soc_register_card failed\n");
+               goto err_put_audio;
+       }
+
+       return 0;
+
+err_put_audio:
+       atmel_ssc_put_audio(tse850->ssc_id);
+err_disable_ana:
+       regulator_disable(tse850->ana);
+       return ret;
+}
+
+static int tse850_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+       atmel_ssc_put_audio(tse850->ssc_id);
+       regulator_disable(tse850->ana);
+
+       return 0;
+}
+
+static const struct of_device_id tse850_dt_ids[] = {
+       { .compatible = "axentia,tse850-pcm5142", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tse850_dt_ids);
+
+static struct platform_driver tse850_driver = {
+       .driver = {
+               .name = "axentia-tse850-pcm5142",
+               .of_match_table = of_match_ptr(tse850_dt_ids),
+       },
+       .probe = tse850_probe,
+       .remove = tse850_remove,
+};
+
+module_platform_driver(tse850_driver);
+
+/* Module information */
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec");
+MODULE_LICENSE("GPL");
index d528aaceaad95bc6bae2147ebe66249629d2512e..edf367100ebd2f1701f4a32b2bfcc14b6cf978d3 100644 (file)
@@ -11,6 +11,7 @@ config SND_BCM2835_SOC_I2S
 config SND_SOC_CYGNUS
        tristate "SoC platform audio for Broadcom Cygnus chips"
        depends on ARCH_BCM_CYGNUS || COMPILE_TEST
+       depends on HAS_DMA
        help
          Say Y if you want to add support for ASoC audio on Broadcom
          Cygnus chips (bcm958300, bcm958305, bcm911360)
index c67667bb970f1729db65b027dd8e963b9ee95b7b..23f31e536c119ca3761af02f857a18578910d246 100644 (file)
@@ -48,6 +48,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
        select SND_SOC_CS35L32 if I2C
        select SND_SOC_CS35L33 if I2C
+       select SND_SOC_CS35L34 if I2C
+       select SND_SOC_CS42L42 if I2C
        select SND_SOC_CS42L51_I2C if I2C
        select SND_SOC_CS42L52 if I2C && INPUT
        select SND_SOC_CS42L56 if I2C && INPUT
@@ -83,6 +85,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX98095 if I2C
        select SND_SOC_MAX98357A if GPIOLIB
        select SND_SOC_MAX98371 if I2C
+       select SND_SOC_MAX98504 if I2C
        select SND_SOC_MAX9867 if I2C
        select SND_SOC_MAX98925 if I2C
        select SND_SOC_MAX98926 if I2C
@@ -114,6 +117,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_RT5651 if I2C
        select SND_SOC_RT5659 if I2C
        select SND_SOC_RT5660 if I2C
+       select SND_SOC_RT5665 if I2C
        select SND_SOC_RT5663 if I2C
        select SND_SOC_RT5670 if I2C
        select SND_SOC_RT5677 if I2C && SPI_MASTER
@@ -399,6 +403,14 @@ config SND_SOC_CS35L33
        tristate "Cirrus Logic CS35L33 CODEC"
        depends on I2C
 
+config SND_SOC_CS35L34
+       tristate "Cirrus Logic CS35L34 CODEC"
+       depends on I2C
+
+config SND_SOC_CS42L42
+       tristate "Cirrus Logic CS42L42 CODEC"
+       depends on I2C
+
 config SND_SOC_CS42L51
        tristate
 
@@ -581,6 +593,13 @@ config SND_SOC_MAX9860
        depends on I2C
        select REGMAP_I2C
 
+config SND_SOC_MSM8916_WCD_ANALOG
+       tristate "Qualcomm MSM8916 WCD Analog Codec"
+       depends on SPMI || COMPILE_TEST
+
+config SND_SOC_MSM8916_WCD_DIGITAL
+       tristate "Qualcomm MSM8916 WCD DIGITAL Codec"
+
 config SND_SOC_PCM1681
        tristate "Texas Instruments PCM1681 CODEC"
        depends on I2C
@@ -649,6 +668,7 @@ config SND_SOC_RL6231
        default y if SND_SOC_RT5651=y
        default y if SND_SOC_RT5659=y
        default y if SND_SOC_RT5660=y
+       default y if SND_SOC_RT5665=y
        default y if SND_SOC_RT5663=y
        default y if SND_SOC_RT5670=y
        default y if SND_SOC_RT5677=y
@@ -659,6 +679,7 @@ config SND_SOC_RL6231
        default m if SND_SOC_RT5651=m
        default m if SND_SOC_RT5659=m
        default m if SND_SOC_RT5660=m
+       default m if SND_SOC_RT5665=m
        default m if SND_SOC_RT5663=m
        default m if SND_SOC_RT5670=m
        default m if SND_SOC_RT5677=m
@@ -672,7 +693,6 @@ config SND_SOC_RL6347A
 
 config SND_SOC_RT286
        tristate
-       select SND_SOC_RT5663
        depends on I2C
 
 config SND_SOC_RT298
@@ -708,6 +728,9 @@ config SND_SOC_RT5659
 config SND_SOC_RT5660
        tristate
 
+config SND_SOC_RT5665
+       tristate
+
 config SND_SOC_RT5663
        tristate
 
index 958cd4912fbc9820f965c0d2f38692857f410d3a..7e1dad79610b39a6d5b83865c7022f09d53d3705 100644 (file)
@@ -38,6 +38,8 @@ snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs35l32-objs := cs35l32.o
 snd-soc-cs35l33-objs := cs35l33.o
+snd-soc-cs35l34-objs := cs35l34.o
+snd-soc-cs42l42-objs := cs42l42.o
 snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
 snd-soc-cs42l52-objs := cs42l52.o
@@ -86,6 +88,8 @@ snd-soc-max9850-objs := max9850.o
 snd-soc-max9860-objs := max9860.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
+snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
+snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
 snd-soc-nau8810-objs := nau8810.o
 snd-soc-nau8825-objs := nau8825.o
 snd-soc-hdmi-codec-objs := hdmi-codec.o
@@ -114,6 +118,7 @@ snd-soc-rt5645-objs := rt5645.o
 snd-soc-rt5651-objs := rt5651.o
 snd-soc-rt5659-objs := rt5659.o
 snd-soc-rt5660-objs := rt5660.o
+snd-soc-rt5665-objs := rt5665.o
 snd-soc-rt5663-objs := rt5663.o
 snd-soc-rt5670-objs := rt5670.o
 snd-soc-rt5677-objs := rt5677.o
@@ -214,7 +219,6 @@ snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
-
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
@@ -263,6 +267,8 @@ obj-$(CONFIG_SND_SOC_BT_SCO)        += snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS35L32)  += snd-soc-cs35l32.o
 obj-$(CONFIG_SND_SOC_CS35L33)  += snd-soc-cs35l33.o
+obj-$(CONFIG_SND_SOC_CS35L34)  += snd-soc-cs35l34.o
+obj-$(CONFIG_SND_SOC_CS42L42)  += snd-soc-cs42l42.o
 obj-$(CONFIG_SND_SOC_CS42L51)  += snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS42L51_I2C)      += snd-soc-cs42l51-i2c.o
 obj-$(CONFIG_SND_SOC_CS42L52)  += snd-soc-cs42l52.o
@@ -310,6 +316,8 @@ obj-$(CONFIG_SND_SOC_MAX9850)       += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MAX9860)  += snd-soc-max9860.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
+obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
 obj-$(CONFIG_SND_SOC_NAU8810)   += snd-soc-nau8810.o
 obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC)       += snd-soc-hdmi-codec.o
@@ -338,6 +346,7 @@ obj-$(CONFIG_SND_SOC_RT5645)        += snd-soc-rt5645.o
 obj-$(CONFIG_SND_SOC_RT5651)   += snd-soc-rt5651.o
 obj-$(CONFIG_SND_SOC_RT5659)   += snd-soc-rt5659.o
 obj-$(CONFIG_SND_SOC_RT5660)   += snd-soc-rt5660.o
+obj-$(CONFIG_SND_SOC_RT5665)   += snd-soc-rt5665.o
 obj-$(CONFIG_SND_SOC_RT5663)   += snd-soc-rt5663.o
 obj-$(CONFIG_SND_SOC_RT5670)   += snd-soc-rt5670.o
 obj-$(CONFIG_SND_SOC_RT5677)   += snd-soc-rt5677.o
index 935ff7cb71c57ca9c458be5a032c0a9e8f190a28..312b2a11abb6a124ccf66778dec2ee7548f76486 100644 (file)
@@ -2587,8 +2587,6 @@ static struct platform_driver ab8500_codec_platform_driver = {
        },
        .probe          = ab8500_codec_driver_probe,
        .remove         = ab8500_codec_driver_remove,
-       .suspend        = NULL,
-       .resume         = NULL,
 };
 module_platform_driver(ab8500_codec_platform_driver);
 
index 439aa3ff1f99cd517f28988f80fe2b34c6489ab2..b36511d965c8202c547a9aaef2827273acc83c28 100644 (file)
@@ -160,7 +160,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *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;
+       struct snd_soc_dapm_update update = { 0 };
        unsigned int stream = e->shift_l;
        unsigned int val, change;
        int reg;
index c91717d08513594d54faef506ec30fe12967fc73..ebdaf56c1d61336d96518f8e4e32aad603cab89c 100644 (file)
 #include <sound/tlv.h>
 #include <sound/ak4641.h>
 
-#include "ak4641.h"
+/* AK4641 register space */
+#define AK4641_PM1             0x00
+#define AK4641_PM2             0x01
+#define AK4641_SIG1            0x02
+#define AK4641_SIG2            0x03
+#define AK4641_MODE1           0x04
+#define AK4641_MODE2           0x05
+#define AK4641_DAC             0x06
+#define AK4641_MIC             0x07
+#define AK4641_TIMER           0x08
+#define AK4641_ALC1            0x09
+#define AK4641_ALC2            0x0a
+#define AK4641_PGA             0x0b
+#define AK4641_LATT            0x0c
+#define AK4641_RATT            0x0d
+#define AK4641_VOL             0x0e
+#define AK4641_STATUS          0x0f
+#define AK4641_EQLO            0x10
+#define AK4641_EQMID           0x11
+#define AK4641_EQHI            0x12
+#define AK4641_BTIF            0x13
 
 /* codec private data */
 struct ak4641_priv {
diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h
deleted file mode 100644 (file)
index 4a26324..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * ak4641.h  --  AK4641 SoC Audio driver
- *
- * Copyright 2008 Harald Welte <laforge@gnufiish.org>
- *
- * Based on ak4535.h
- *
- * 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 _AK4641_H
-#define _AK4641_H
-
-/* AK4641 register space */
-
-#define AK4641_PM1             0x00
-#define AK4641_PM2             0x01
-#define AK4641_SIG1            0x02
-#define AK4641_SIG2            0x03
-#define AK4641_MODE1           0x04
-#define AK4641_MODE2           0x05
-#define AK4641_DAC             0x06
-#define AK4641_MIC             0x07
-#define AK4641_TIMER           0x08
-#define AK4641_ALC1            0x09
-#define AK4641_ALC2            0x0a
-#define AK4641_PGA             0x0b
-#define AK4641_LATT            0x0c
-#define AK4641_RATT            0x0d
-#define AK4641_VOL             0x0e
-#define AK4641_STATUS          0x0f
-#define AK4641_EQLO            0x10
-#define AK4641_EQMID           0x11
-#define AK4641_EQHI            0x12
-#define AK4641_BTIF            0x13
-
-#define AK4641_CACHEREGNUM     0x14
-
-
-
-#define AK4641_DAI_HIFI                0
-#define AK4641_DAI_VOICE       1
-
-
-#endif
index 846ca079845fa8d141411e6944f369e904e95b61..0a734d910850b1305b1fa5ee67efc571576bfbf5 100644 (file)
@@ -191,6 +191,14 @@ int arizona_init_spk(struct snd_soc_codec *codec)
                break;
        }
 
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_spk);
+
+int arizona_init_spk_irqs(struct arizona *arizona)
+{
+       int ret;
+
        ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
                                  "Thermal warning", arizona_thermal_warn,
                                  arizona);
@@ -209,19 +217,16 @@ int arizona_init_spk(struct snd_soc_codec *codec)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(arizona_init_spk);
+EXPORT_SYMBOL_GPL(arizona_init_spk_irqs);
 
-int arizona_free_spk(struct snd_soc_codec *codec)
+int arizona_free_spk_irqs(struct arizona *arizona)
 {
-       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->arizona;
-
        arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);
        arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(arizona_free_spk);
+EXPORT_SYMBOL_GPL(arizona_free_spk_irqs);
 
 static const struct snd_soc_dapm_route arizona_mono_routes[] = {
        { "OUT1R", NULL, "OUT1L" },
@@ -252,6 +257,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 snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona *arizona = priv->arizona;
        int i;
@@ -259,21 +265,24 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
        switch (arizona->type) {
        case WM5110:
        case WM8280:
-               snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
+               snd_soc_component_disable_pin(component,
+                                             "DRC2 Signal Activity");
                break;
        default:
                break;
        }
 
-       snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
+       snd_soc_component_disable_pin(component, "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(dapm, "DRC1 Signal Activity");
+                       snd_soc_component_enable_pin(component,
+                                                    "DRC1 Signal Activity");
                        break;
                case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
-                       snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
+                       snd_soc_component_enable_pin(component,
+                                                    "DRC2 Signal Activity");
                        break;
                default:
                        break;
@@ -1233,6 +1242,46 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
        return -EINVAL;
 }
 
+int arizona_clk_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 val;
+       int clk_idx;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, w->reg, &val);
+       if (ret) {
+               dev_err(codec->dev, "Failed to check clock source: %d\n", ret);
+               return ret;
+       }
+
+       val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT;
+
+       switch (val) {
+       case ARIZONA_CLK_SRC_MCLK1:
+               clk_idx = ARIZONA_MCLK1;
+               break;
+       case ARIZONA_CLK_SRC_MCLK2:
+               clk_idx = ARIZONA_MCLK2;
+               break;
+       default:
+               return 0;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               return clk_prepare_enable(arizona->mclk[clk_idx]);
+       case SND_SOC_DAPM_POST_PMD:
+               clk_disable_unprepare(arizona->mclk[clk_idx]);
+               return 0;
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(arizona_clk_ev);
+
 int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                       int source, unsigned int freq, int dir)
 {
@@ -2242,6 +2291,42 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
        return reg & ARIZONA_FLL1_ENA;
 }
 
+static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena)
+{
+       struct arizona *arizona = fll->arizona;
+       unsigned int val;
+       struct clk *clk;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, base + 6, &val);
+       if (ret != 0) {
+               arizona_fll_err(fll, "Failed to read current source: %d\n",
+                               ret);
+               return ret;
+       }
+
+       val &= ARIZONA_FLL1_CLK_REF_SRC_MASK;
+       val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT;
+
+       switch (val) {
+       case ARIZONA_FLL_SRC_MCLK1:
+               clk = arizona->mclk[ARIZONA_MCLK1];
+               break;
+       case ARIZONA_FLL_SRC_MCLK2:
+               clk = arizona->mclk[ARIZONA_MCLK2];
+               break;
+       default:
+               return 0;
+       }
+
+       if (ena) {
+               return clk_prepare_enable(clk);
+       } else {
+               clk_disable_unprepare(clk);
+               return 0;
+       }
+}
+
 static int arizona_enable_fll(struct arizona_fll *fll)
 {
        struct arizona *arizona = fll->arizona;
@@ -2264,6 +2349,10 @@ static int arizona_enable_fll(struct arizona_fll *fll)
                udelay(32);
                regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
                                         ARIZONA_FLL1_GAIN_MASK, 0);
+
+               if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0)
+                       arizona_set_fll_clks(fll, fll->base + 0x10, false);
+               arizona_set_fll_clks(fll, fll->base, false);
        }
 
        /*
@@ -2318,10 +2407,13 @@ static int arizona_enable_fll(struct arizona_fll *fll)
        if (!already_enabled)
                pm_runtime_get_sync(arizona->dev);
 
-       if (use_sync)
+       if (use_sync) {
+               arizona_set_fll_clks(fll, fll->base + 0x10, true);
                regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
                                         ARIZONA_FLL1_SYNC_ENA,
                                         ARIZONA_FLL1_SYNC_ENA);
+       }
+       arizona_set_fll_clks(fll, fll->base, true);
        regmap_update_bits_async(arizona->regmap, fll->base + 1,
                                 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
 
@@ -2354,19 +2446,24 @@ static int arizona_enable_fll(struct arizona_fll *fll)
 static void arizona_disable_fll(struct arizona_fll *fll)
 {
        struct arizona *arizona = fll->arizona;
-       bool change;
+       bool ref_change, sync_change;
 
        regmap_update_bits_async(arizona->regmap, fll->base + 1,
                                 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
        regmap_update_bits_check(arizona->regmap, fll->base + 1,
-                                ARIZONA_FLL1_ENA, 0, &change);
-       regmap_update_bits(arizona->regmap, fll->base + 0x11,
-                          ARIZONA_FLL1_SYNC_ENA, 0);
+                                ARIZONA_FLL1_ENA, 0, &ref_change);
+       regmap_update_bits_check(arizona->regmap, fll->base + 0x11,
+                                ARIZONA_FLL1_SYNC_ENA, 0, &sync_change);
        regmap_update_bits_async(arizona->regmap, fll->base + 1,
                                 ARIZONA_FLL1_FREERUN, 0);
 
-       if (change)
+       if (sync_change)
+               arizona_set_fll_clks(fll, fll->base + 0x10, false);
+
+       if (ref_change) {
+               arizona_set_fll_clks(fll, fll->base, false);
                pm_runtime_put_autosuspend(arizona->dev);
+       }
 }
 
 int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
@@ -2598,30 +2695,6 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
 
-int arizona_register_notifier(struct snd_soc_codec *codec,
-                             struct notifier_block *nb,
-                             int (*notify)(struct notifier_block *nb,
-                                           unsigned long action, void *data))
-{
-       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->arizona;
-
-       nb->notifier_call = notify;
-
-       return blocking_notifier_chain_register(&arizona->notifier, nb);
-}
-EXPORT_SYMBOL_GPL(arizona_register_notifier);
-
-int arizona_unregister_notifier(struct snd_soc_codec *codec,
-                               struct notifier_block *nb)
-{
-       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->arizona;
-
-       return blocking_notifier_chain_unregister(&arizona->notifier, nb);
-}
-EXPORT_SYMBOL_GPL(arizona_unregister_notifier);
-
 MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
index 850aa338ba293e2dca4b47f81fc93662e238bd50..56707860657cca129df30ed0d64d4081efdedbbf 100644 (file)
@@ -14,6 +14,8 @@
 #define _ASOC_ARIZONA_H
 
 #include <linux/completion.h>
+#include <linux/notifier.h>
+#include <linux/mfd/arizona/core.h>
 
 #include <sound/soc.h>
 
@@ -66,7 +68,6 @@
 /* Notifier events */
 #define ARIZONA_NOTIFY_VOICE_TRIGGER   0x1
 
-struct arizona;
 struct wm_adsp;
 
 struct arizona_dai_priv {
@@ -255,26 +256,24 @@ extern const struct soc_enum arizona_output_anc_src[];
 
 extern const struct snd_kcontrol_new arizona_voice_trigger_switch[];
 
-extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *kcontrol,
-                        int event);
-extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
-                         struct snd_kcontrol *kcontrol,
-                         int event);
-extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
-                        struct snd_kcontrol *kcontrol,
-                        int event);
-extern int arizona_anc_ev(struct snd_soc_dapm_widget *w,
-                         struct snd_kcontrol *kcontrol,
-                         int event);
-
-extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol);
-extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol);
-
-extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
-                             int source, unsigned int freq, int dir);
+int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+                 int event);
+int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+                  int event);
+int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+                 int event);
+int arizona_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+                  int event);
+
+int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol);
+int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol);
+
+int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
+                  int event);
+int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source,
+                      unsigned int freq, int dir);
 
 extern const struct snd_soc_dai_ops arizona_dai_ops;
 extern const struct snd_soc_dai_ops arizona_simple_dai_ops;
@@ -297,41 +296,57 @@ 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,
-                                 unsigned int Fref, unsigned int Fout);
-extern int arizona_set_fll(struct arizona_fll *fll, int source,
+int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
+int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
+int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event);
+void arizona_init_dvfs(struct arizona_priv *priv);
+
+int arizona_init_fll(struct arizona *arizona, int id, int base,
+                    int lock_irq, int ok_irq, struct arizona_fll *fll);
+int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
                           unsigned int Fref, unsigned int Fout);
+int arizona_set_fll(struct arizona_fll *fll, int source,
+                   unsigned int Fref, unsigned int Fout);
 
-extern int arizona_init_spk(struct snd_soc_codec *codec);
-extern int arizona_init_gpio(struct snd_soc_codec *codec);
-extern int arizona_init_mono(struct snd_soc_codec *codec);
-extern int arizona_init_notifiers(struct snd_soc_codec *codec);
+int arizona_init_spk(struct snd_soc_codec *codec);
+int arizona_init_gpio(struct snd_soc_codec *codec);
+int arizona_init_mono(struct snd_soc_codec *codec);
+int arizona_init_notifiers(struct snd_soc_codec *codec);
 
-extern int arizona_free_spk(struct snd_soc_codec *codec);
+int arizona_init_spk_irqs(struct arizona *arizona);
+int arizona_free_spk_irqs(struct arizona *arizona);
 
-extern int arizona_init_dai(struct arizona_priv *priv, int dai);
+int arizona_init_dai(struct arizona_priv *priv, int dai);
 
 int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
                            bool diff);
 
-extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
+bool arizona_input_analog(struct snd_soc_codec *codec, int shift);
+
+const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
+
+static inline int arizona_register_notifier(struct snd_soc_codec *codec,
+                                           struct notifier_block *nb,
+                                           int (*notify)
+                                           (struct notifier_block *nb,
+                                           unsigned long action, void *data))
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+
+       nb->notifier_call = notify;
+
+       return blocking_notifier_chain_register(&arizona->notifier, nb);
+}
 
-extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val);
+static inline int arizona_unregister_notifier(struct snd_soc_codec *codec,
+                                             struct notifier_block *nb)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
 
-extern int arizona_register_notifier(struct snd_soc_codec *codec,
-                                    struct notifier_block *nb,
-                                    int (*notify)(struct notifier_block *nb,
-                                                  unsigned long action,
-                                                  void *data));
-extern int arizona_unregister_notifier(struct snd_soc_codec *codec,
-                                      struct notifier_block *nb);
+       return blocking_notifier_chain_unregister(&arizona->notifier, nb);
+}
 
 #endif
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
new file mode 100644 (file)
index 0000000..7c5d151
--- /dev/null
@@ -0,0 +1,1251 @@
+/*
+ * cs35l34.c -- CS35l34 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <Paul.Handrigan@cirrus.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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs35l34.h>
+
+#include "cs35l34.h"
+
+#define PDN_DONE_ATTEMPTS 10
+#define CS35L34_START_DELAY 50
+
+struct  cs35l34_private {
+       struct snd_soc_codec *codec;
+       struct cs35l34_platform_data pdata;
+       struct regmap *regmap;
+       struct regulator_bulk_data core_supplies[2];
+       int num_core_supplies;
+       int mclk_int;
+       bool tdm_mode;
+       struct gpio_desc *reset_gpio;   /* Active-low reset GPIO */
+};
+
+static const struct reg_default cs35l34_reg[] = {
+       {CS35L34_PWRCTL1, 0x01},
+       {CS35L34_PWRCTL2, 0x19},
+       {CS35L34_PWRCTL3, 0x01},
+       {CS35L34_ADSP_CLK_CTL, 0x08},
+       {CS35L34_MCLK_CTL, 0x11},
+       {CS35L34_AMP_INP_DRV_CTL, 0x01},
+       {CS35L34_AMP_DIG_VOL_CTL, 0x12},
+       {CS35L34_AMP_DIG_VOL, 0x00},
+       {CS35L34_AMP_ANLG_GAIN_CTL, 0x0F},
+       {CS35L34_PROTECT_CTL, 0x06},
+       {CS35L34_AMP_KEEP_ALIVE_CTL, 0x04},
+       {CS35L34_BST_CVTR_V_CTL, 0x00},
+       {CS35L34_BST_PEAK_I, 0x10},
+       {CS35L34_BST_RAMP_CTL, 0x87},
+       {CS35L34_BST_CONV_COEF_1, 0x24},
+       {CS35L34_BST_CONV_COEF_2, 0x24},
+       {CS35L34_BST_CONV_SLOPE_COMP, 0x4E},
+       {CS35L34_BST_CONV_SW_FREQ, 0x08},
+       {CS35L34_CLASS_H_CTL, 0x0D},
+       {CS35L34_CLASS_H_HEADRM_CTL, 0x0D},
+       {CS35L34_CLASS_H_RELEASE_RATE, 0x08},
+       {CS35L34_CLASS_H_FET_DRIVE_CTL, 0x41},
+       {CS35L34_CLASS_H_STATUS, 0x05},
+       {CS35L34_VPBR_CTL, 0x0A},
+       {CS35L34_VPBR_VOL_CTL, 0x90},
+       {CS35L34_VPBR_TIMING_CTL, 0x6A},
+       {CS35L34_PRED_MAX_ATTEN_SPK_LOAD, 0x95},
+       {CS35L34_PRED_BROWNOUT_THRESH, 0x1C},
+       {CS35L34_PRED_BROWNOUT_VOL_CTL, 0x00},
+       {CS35L34_PRED_BROWNOUT_RATE_CTL, 0x10},
+       {CS35L34_PRED_WAIT_CTL, 0x10},
+       {CS35L34_PRED_ZVP_INIT_IMP_CTL, 0x08},
+       {CS35L34_PRED_MAN_SAFE_VPI_CTL, 0x80},
+       {CS35L34_VPBR_ATTEN_STATUS, 0x00},
+       {CS35L34_PRED_BRWNOUT_ATT_STATUS, 0x00},
+       {CS35L34_SPKR_MON_CTL, 0xC6},
+       {CS35L34_ADSP_I2S_CTL, 0x00},
+       {CS35L34_ADSP_TDM_CTL, 0x00},
+       {CS35L34_TDM_TX_CTL_1_VMON, 0x00},
+       {CS35L34_TDM_TX_CTL_2_IMON, 0x04},
+       {CS35L34_TDM_TX_CTL_3_VPMON, 0x03},
+       {CS35L34_TDM_TX_CTL_4_VBSTMON, 0x07},
+       {CS35L34_TDM_TX_CTL_5_FLAG1, 0x08},
+       {CS35L34_TDM_TX_CTL_6_FLAG2, 0x09},
+       {CS35L34_TDM_TX_SLOT_EN_1, 0x00},
+       {CS35L34_TDM_TX_SLOT_EN_2, 0x00},
+       {CS35L34_TDM_TX_SLOT_EN_3, 0x00},
+       {CS35L34_TDM_TX_SLOT_EN_4, 0x00},
+       {CS35L34_TDM_RX_CTL_1_AUDIN, 0x40},
+       {CS35L34_TDM_RX_CTL_3_ALIVE, 0x04},
+       {CS35L34_MULT_DEV_SYNCH1, 0x00},
+       {CS35L34_MULT_DEV_SYNCH2, 0x80},
+       {CS35L34_PROT_RELEASE_CTL, 0x00},
+       {CS35L34_DIAG_MODE_REG_LOCK, 0x00},
+       {CS35L34_DIAG_MODE_CTL_1, 0x00},
+       {CS35L34_DIAG_MODE_CTL_2, 0x00},
+       {CS35L34_INT_MASK_1, 0xFF},
+       {CS35L34_INT_MASK_2, 0xFF},
+       {CS35L34_INT_MASK_3, 0xFF},
+       {CS35L34_INT_MASK_4, 0xFF},
+       {CS35L34_INT_STATUS_1, 0x30},
+       {CS35L34_INT_STATUS_2, 0x05},
+       {CS35L34_INT_STATUS_3, 0x00},
+       {CS35L34_INT_STATUS_4, 0x00},
+       {CS35L34_OTP_TRIM_STATUS, 0x00},
+};
+
+static bool cs35l34_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS35L34_DEVID_AB:
+       case CS35L34_DEVID_CD:
+       case CS35L34_DEVID_E:
+       case CS35L34_FAB_ID:
+       case CS35L34_REV_ID:
+       case CS35L34_INT_STATUS_1:
+       case CS35L34_INT_STATUS_2:
+       case CS35L34_INT_STATUS_3:
+       case CS35L34_INT_STATUS_4:
+       case CS35L34_CLASS_H_STATUS:
+       case CS35L34_VPBR_ATTEN_STATUS:
+       case CS35L34_OTP_TRIM_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs35l34_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case    CS35L34_DEVID_AB:
+       case    CS35L34_DEVID_CD:
+       case    CS35L34_DEVID_E:
+       case    CS35L34_FAB_ID:
+       case    CS35L34_REV_ID:
+       case    CS35L34_PWRCTL1:
+       case    CS35L34_PWRCTL2:
+       case    CS35L34_PWRCTL3:
+       case    CS35L34_ADSP_CLK_CTL:
+       case    CS35L34_MCLK_CTL:
+       case    CS35L34_AMP_INP_DRV_CTL:
+       case    CS35L34_AMP_DIG_VOL_CTL:
+       case    CS35L34_AMP_DIG_VOL:
+       case    CS35L34_AMP_ANLG_GAIN_CTL:
+       case    CS35L34_PROTECT_CTL:
+       case    CS35L34_AMP_KEEP_ALIVE_CTL:
+       case    CS35L34_BST_CVTR_V_CTL:
+       case    CS35L34_BST_PEAK_I:
+       case    CS35L34_BST_RAMP_CTL:
+       case    CS35L34_BST_CONV_COEF_1:
+       case    CS35L34_BST_CONV_COEF_2:
+       case    CS35L34_BST_CONV_SLOPE_COMP:
+       case    CS35L34_BST_CONV_SW_FREQ:
+       case    CS35L34_CLASS_H_CTL:
+       case    CS35L34_CLASS_H_HEADRM_CTL:
+       case    CS35L34_CLASS_H_RELEASE_RATE:
+       case    CS35L34_CLASS_H_FET_DRIVE_CTL:
+       case    CS35L34_CLASS_H_STATUS:
+       case    CS35L34_VPBR_CTL:
+       case    CS35L34_VPBR_VOL_CTL:
+       case    CS35L34_VPBR_TIMING_CTL:
+       case    CS35L34_PRED_MAX_ATTEN_SPK_LOAD:
+       case    CS35L34_PRED_BROWNOUT_THRESH:
+       case    CS35L34_PRED_BROWNOUT_VOL_CTL:
+       case    CS35L34_PRED_BROWNOUT_RATE_CTL:
+       case    CS35L34_PRED_WAIT_CTL:
+       case    CS35L34_PRED_ZVP_INIT_IMP_CTL:
+       case    CS35L34_PRED_MAN_SAFE_VPI_CTL:
+       case    CS35L34_VPBR_ATTEN_STATUS:
+       case    CS35L34_PRED_BRWNOUT_ATT_STATUS:
+       case    CS35L34_SPKR_MON_CTL:
+       case    CS35L34_ADSP_I2S_CTL:
+       case    CS35L34_ADSP_TDM_CTL:
+       case    CS35L34_TDM_TX_CTL_1_VMON:
+       case    CS35L34_TDM_TX_CTL_2_IMON:
+       case    CS35L34_TDM_TX_CTL_3_VPMON:
+       case    CS35L34_TDM_TX_CTL_4_VBSTMON:
+       case    CS35L34_TDM_TX_CTL_5_FLAG1:
+       case    CS35L34_TDM_TX_CTL_6_FLAG2:
+       case    CS35L34_TDM_TX_SLOT_EN_1:
+       case    CS35L34_TDM_TX_SLOT_EN_2:
+       case    CS35L34_TDM_TX_SLOT_EN_3:
+       case    CS35L34_TDM_TX_SLOT_EN_4:
+       case    CS35L34_TDM_RX_CTL_1_AUDIN:
+       case    CS35L34_TDM_RX_CTL_3_ALIVE:
+       case    CS35L34_MULT_DEV_SYNCH1:
+       case    CS35L34_MULT_DEV_SYNCH2:
+       case    CS35L34_PROT_RELEASE_CTL:
+       case    CS35L34_DIAG_MODE_REG_LOCK:
+       case    CS35L34_DIAG_MODE_CTL_1:
+       case    CS35L34_DIAG_MODE_CTL_2:
+       case    CS35L34_INT_MASK_1:
+       case    CS35L34_INT_MASK_2:
+       case    CS35L34_INT_MASK_3:
+       case    CS35L34_INT_MASK_4:
+       case    CS35L34_INT_STATUS_1:
+       case    CS35L34_INT_STATUS_2:
+       case    CS35L34_INT_STATUS_3:
+       case    CS35L34_INT_STATUS_4:
+       case    CS35L34_OTP_TRIM_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs35l34_precious_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS35L34_INT_STATUS_1:
+       case CS35L34_INT_STATUS_2:
+       case CS35L34_INT_STATUS_3:
+       case CS35L34_INT_STATUS_4:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (priv->tdm_mode)
+                       regmap_update_bits(priv->regmap, CS35L34_PWRCTL3,
+                                               CS35L34_PDN_TDM, 0x00);
+
+               ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1,
+                                               CS35L34_PDN_ALL, 0);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Cannot set Power bits %d\n", ret);
+                       return ret;
+               }
+               usleep_range(5000, 5100);
+       break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (priv->tdm_mode) {
+                       regmap_update_bits(priv->regmap, CS35L34_PWRCTL3,
+                                       CS35L34_PDN_TDM, CS35L34_PDN_TDM);
+               }
+               ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1,
+                                       CS35L34_PDN_ALL, CS35L34_PDN_ALL);
+       break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
+static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                               unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg, bit_pos;
+       int slot, slot_num;
+
+       if (slot_width != 8)
+               return -EINVAL;
+
+       priv->tdm_mode = true;
+       /* scan rx_mask for aud slot */
+       slot = ffs(rx_mask) - 1;
+       if (slot >= 0)
+               snd_soc_update_bits(codec, CS35L34_TDM_RX_CTL_1_AUDIN,
+                                       CS35L34_X_LOC, slot);
+
+       /* scan tx_mask: vmon(2 slots); imon (2 slots); vpmon (1 slot)
+        * vbstmon (1 slot)
+        */
+       slot = ffs(tx_mask) - 1;
+       slot_num = 0;
+
+       /* disable vpmon/vbstmon: enable later if set in tx_mask */
+       snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON,
+                               CS35L34_X_STATE | CS35L34_X_LOC,
+                               CS35L34_X_STATE | CS35L34_X_LOC);
+       snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_4_VBSTMON,
+                               CS35L34_X_STATE | CS35L34_X_LOC,
+                               CS35L34_X_STATE | CS35L34_X_LOC);
+
+       /* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/
+       while (slot >= 0) {
+               /* configure VMON_TX_LOC */
+               if (slot_num == 0)
+                       snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_1_VMON,
+                                       CS35L34_X_STATE | CS35L34_X_LOC, slot);
+
+               /* configure IMON_TX_LOC */
+               if (slot_num == 4) {
+                       snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_2_IMON,
+                                       CS35L34_X_STATE | CS35L34_X_LOC, slot);
+               }
+               /* configure VPMON_TX_LOC */
+               if (slot_num == 3) {
+                       snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON,
+                                       CS35L34_X_STATE | CS35L34_X_LOC, slot);
+               }
+               /* configure VBSTMON_TX_LOC */
+               if (slot_num == 7) {
+                       snd_soc_update_bits(codec,
+                               CS35L34_TDM_TX_CTL_4_VBSTMON,
+                               CS35L34_X_STATE | CS35L34_X_LOC, slot);
+               }
+
+               /* Enable the relevant tx slot */
+               reg = CS35L34_TDM_TX_SLOT_EN_4 - (slot/8);
+               bit_pos = slot - ((slot / 8) * (8));
+               snd_soc_update_bits(codec, reg,
+                       1 << bit_pos, 1 << bit_pos);
+
+               tx_mask &= ~(1 << slot);
+               slot = ffs(tx_mask) - 1;
+               slot_num++;
+       }
+
+       return 0;
+}
+
+static int cs35l34_main_amp_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL,
+                               CS35L34_BST_CVTL_MASK, priv->pdata.boost_vtge);
+               usleep_range(5000, 5100);
+               regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL,
+                                               CS35L34_MUTE, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL,
+                       CS35L34_BST_CVTL_MASK, 0);
+               regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL,
+                       CS35L34_MUTE, CS35L34_MUTE);
+               usleep_range(5000, 5100);
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
+static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 300, 100, 0);
+
+
+static const struct snd_kcontrol_new cs35l34_snd_controls[] = {
+       SOC_SINGLE_SX_TLV("Digital Volume", CS35L34_AMP_DIG_VOL,
+                     0, 0x34, 0xE4, dig_vol_tlv),
+       SOC_SINGLE_TLV("Amp Gain Volume", CS35L34_AMP_ANLG_GAIN_CTL,
+                     0, 0xF, 0, amp_gain_tlv),
+};
+
+
+static int cs35l34_mclk_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+       int ret, i;
+       unsigned int reg;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+               ret = regmap_read(priv->regmap, CS35L34_AMP_DIG_VOL_CTL,
+                       &reg);
+               if (ret != 0) {
+                       pr_err("%s regmap read failure %d\n", __func__, ret);
+                       return ret;
+               }
+               if (reg & CS35L34_AMP_DIGSFT)
+                       msleep(40);
+               else
+                       usleep_range(2000, 2100);
+
+               for (i = 0; i < PDN_DONE_ATTEMPTS; i++) {
+                       ret = regmap_read(priv->regmap, CS35L34_INT_STATUS_2,
+                               &reg);
+                       if (ret != 0) {
+                               pr_err("%s regmap read failure %d\n",
+                                       __func__, ret);
+                               return ret;
+                       }
+                       if (reg & CS35L34_PDN_DONE)
+                               break;
+
+                       usleep_range(5000, 5100);
+               }
+               if (i == PDN_DONE_ATTEMPTS)
+                       pr_err("%s Device did not power down properly\n",
+                               __func__);
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+               break;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget cs35l34_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L34_PWRCTL3,
+                                       1, 1, cs35l34_sdin_event,
+                                       SND_SOC_DAPM_PRE_PMU |
+                                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L34_PWRCTL3, 2, 1),
+
+       SND_SOC_DAPM_SUPPLY("EXTCLK", CS35L34_PWRCTL3, 7, 1,
+               cs35l34_mclk_event, SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_OUTPUT("SPK"),
+
+       SND_SOC_DAPM_INPUT("VP"),
+       SND_SOC_DAPM_INPUT("VPST"),
+       SND_SOC_DAPM_INPUT("ISENSE"),
+       SND_SOC_DAPM_INPUT("VSENSE"),
+
+       SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L34_PWRCTL2, 7, 1),
+       SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L34_PWRCTL2, 6, 1),
+       SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L34_PWRCTL3, 3, 1),
+       SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L34_PWRCTL3, 4, 1),
+       SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L34_PWRCTL2, 5, 1),
+       SND_SOC_DAPM_ADC("BOOST", NULL, CS35L34_PWRCTL2, 2, 1),
+
+       SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L34_PWRCTL2, 0, 1, NULL, 0,
+               cs35l34_main_amp_event, SND_SOC_DAPM_POST_PMU |
+                       SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route cs35l34_audio_map[] = {
+       {"SDIN", NULL, "AMP Playback"},
+       {"BOOST", NULL, "SDIN"},
+       {"CLASS H", NULL, "BOOST"},
+       {"Main AMP", NULL, "CLASS H"},
+       {"SPK", NULL, "Main AMP"},
+
+       {"VPMON ADC", NULL, "CLASS H"},
+       {"VBSTMON ADC", NULL, "CLASS H"},
+       {"SPK", NULL, "VPMON ADC"},
+       {"SPK", NULL, "VBSTMON ADC"},
+
+       {"IMON ADC", NULL, "ISENSE"},
+       {"VMON ADC", NULL, "VSENSE"},
+       {"SDOUT", NULL, "IMON ADC"},
+       {"SDOUT", NULL, "VMON ADC"},
+       {"AMP Capture", NULL, "SDOUT"},
+
+       {"SDIN", NULL, "EXTCLK"},
+       {"SDOUT", NULL, "EXTCLK"},
+};
+
+struct cs35l34_mclk_div {
+       int mclk;
+       int srate;
+       u8 adsp_rate;
+};
+
+static struct cs35l34_mclk_div cs35l34_mclk_coeffs[] = {
+
+       /* MCLK, Sample Rate, adsp_rate */
+
+       {5644800, 11025, 0x1},
+       {5644800, 22050, 0x4},
+       {5644800, 44100, 0x7},
+
+       {6000000,  8000, 0x0},
+       {6000000, 11025, 0x1},
+       {6000000, 12000, 0x2},
+       {6000000, 16000, 0x3},
+       {6000000, 22050, 0x4},
+       {6000000, 24000, 0x5},
+       {6000000, 32000, 0x6},
+       {6000000, 44100, 0x7},
+       {6000000, 48000, 0x8},
+
+       {6144000,  8000, 0x0},
+       {6144000, 11025, 0x1},
+       {6144000, 12000, 0x2},
+       {6144000, 16000, 0x3},
+       {6144000, 22050, 0x4},
+       {6144000, 24000, 0x5},
+       {6144000, 32000, 0x6},
+       {6144000, 44100, 0x7},
+       {6144000, 48000, 0x8},
+};
+
+static int cs35l34_get_mclk_coeff(int mclk, int srate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(cs35l34_mclk_coeffs); i++) {
+               if (cs35l34_mclk_coeffs[i].mclk == mclk &&
+                       cs35l34_mclk_coeffs[i].srate == srate)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
+                                   0x80, 0x80);
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
+                                   0x80, 0x00);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec);
+       int srate = params_rate(params);
+       int ret;
+
+       int coeff = cs35l34_get_mclk_coeff(priv->mclk_int, srate);
+
+       if (coeff < 0) {
+               dev_err(codec->dev, "ERROR: Invalid mclk %d and/or srate %d\n",
+                       priv->mclk_int, srate);
+               return coeff;
+       }
+
+       ret = regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
+               CS35L34_ADSP_RATE, cs35l34_mclk_coeffs[coeff].adsp_rate);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to set clock state %d\n", ret);
+
+       return ret;
+}
+
+static unsigned int cs35l34_src_rates[] = {
+       8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+
+static struct snd_pcm_hw_constraint_list cs35l34_constraints = {
+       .count  = ARRAY_SIZE(cs35l34_src_rates),
+       .list   = cs35l34_src_rates,
+};
+
+static int cs35l34_pcm_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, &cs35l34_constraints);
+       return 0;
+}
+
+
+static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+
+       struct snd_soc_codec *codec = dai->codec;
+
+       if (tristate)
+               snd_soc_update_bits(codec, CS35L34_PWRCTL3,
+                                       CS35L34_PDN_SDOUT, CS35L34_PDN_SDOUT);
+       else
+               snd_soc_update_bits(codec, CS35L34_PWRCTL3,
+                                       CS35L34_PDN_SDOUT, 0);
+       return 0;
+}
+
+static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec);
+       unsigned int value;
+
+       switch (freq) {
+       case CS35L34_MCLK_5644:
+               value = CS35L34_MCLK_RATE_5P6448;
+               cs35l34->mclk_int = freq;
+       break;
+       case CS35L34_MCLK_6:
+               value = CS35L34_MCLK_RATE_6P0000;
+               cs35l34->mclk_int = freq;
+       break;
+       case CS35L34_MCLK_6144:
+               value = CS35L34_MCLK_RATE_6P1440;
+               cs35l34->mclk_int = freq;
+       break;
+       case CS35L34_MCLK_11289:
+               value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_5P6448;
+               cs35l34->mclk_int = freq / 2;
+       break;
+       case CS35L34_MCLK_12:
+               value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P0000;
+               cs35l34->mclk_int = freq / 2;
+       break;
+       case CS35L34_MCLK_12288:
+               value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P1440;
+               cs35l34->mclk_int = freq / 2;
+       break;
+       default:
+               dev_err(codec->dev, "ERROR: Invalid Frequency %d\n", freq);
+               cs35l34->mclk_int = 0;
+               return -EINVAL;
+       }
+       regmap_update_bits(cs35l34->regmap, CS35L34_MCLK_CTL,
+                       CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_MASK, value);
+       return 0;
+}
+
+static const struct snd_soc_dai_ops cs35l34_ops = {
+       .startup = cs35l34_pcm_startup,
+       .set_tristate = cs35l34_set_tristate,
+       .set_fmt = cs35l34_set_dai_fmt,
+       .hw_params = cs35l34_pcm_hw_params,
+       .set_sysclk = cs35l34_dai_set_sysclk,
+       .set_tdm_slot = cs35l34_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver cs35l34_dai = {
+               .name = "cs35l34",
+               .id = 0,
+               .playback = {
+                       .stream_name = "AMP Playback",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = CS35L34_RATES,
+                       .formats = CS35L34_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AMP Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = CS35L34_RATES,
+                       .formats = CS35L34_FORMATS,
+               },
+               .ops = &cs35l34_ops,
+               .symmetric_rates = 1,
+};
+
+static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34,
+       unsigned int inductor)
+{
+       struct snd_soc_codec *codec = cs35l34->codec;
+
+       switch (inductor) {
+       case 1000: /* 1 uH */
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x24);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x24);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+                       0x4E);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 0);
+               break;
+       case 1200: /* 1.2 uH */
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+                       0x47);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 1);
+               break;
+       case 1500: /* 1.5uH */
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+                       0x3C);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 2);
+               break;
+       case 2200: /* 2.2uH */
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x19);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x25);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP,
+                       0x23);
+               regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 3);
+               break;
+       default:
+               dev_err(codec->dev, "%s Invalid Inductor Value %d uH\n",
+                       __func__, inductor);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int cs35l34_probe(struct snd_soc_codec *codec)
+{
+       int ret = 0;
+       struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec);
+
+       pm_runtime_get_sync(codec->dev);
+
+       /* Set over temperature warning attenuation to 6 dB */
+       regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+                CS35L34_OTW_ATTN_MASK, 0x8);
+
+       /* Set Power control registers 2 and 3 to have everything
+        * powered down at initialization
+        */
+       regmap_write(cs35l34->regmap, CS35L34_PWRCTL2, 0xFD);
+       regmap_write(cs35l34->regmap, CS35L34_PWRCTL3, 0x1F);
+
+       /* Set mute bit at startup */
+       regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+                               CS35L34_MUTE, CS35L34_MUTE);
+
+       /* Set Platform Data */
+       if (cs35l34->pdata.boost_peak)
+               regmap_update_bits(cs35l34->regmap, CS35L34_BST_PEAK_I,
+                               CS35L34_BST_PEAK_MASK,
+                               cs35l34->pdata.boost_peak);
+
+       if (cs35l34->pdata.gain_zc_disable)
+               regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+                       CS35L34_GAIN_ZC_MASK, 0);
+       else
+               regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL,
+                       CS35L34_GAIN_ZC_MASK, CS35L34_GAIN_ZC_MASK);
+
+       if (cs35l34->pdata.aif_half_drv)
+               regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_CLK_CTL,
+                       CS35L34_ADSP_DRIVE, 0);
+
+       if (cs35l34->pdata.digsft_disable)
+               regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL,
+                       CS35L34_AMP_DIGSFT, 0);
+
+       if (cs35l34->pdata.amp_inv)
+               regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL,
+                       CS35L34_INV, CS35L34_INV);
+
+       if (cs35l34->pdata.boost_ind)
+               ret = cs35l34_boost_inductor(cs35l34, cs35l34->pdata.boost_ind);
+
+       if (cs35l34->pdata.i2s_sdinloc)
+               regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_I2S_CTL,
+                       CS35L34_I2S_LOC_MASK,
+                       cs35l34->pdata.i2s_sdinloc << CS35L34_I2S_LOC_SHIFT);
+
+       if (cs35l34->pdata.tdm_rising_edge)
+               regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_TDM_CTL,
+                       1, 1);
+
+       pm_runtime_put_sync(codec->dev);
+
+       return ret;
+}
+
+
+static struct snd_soc_codec_driver soc_codec_dev_cs35l34 = {
+       .probe = cs35l34_probe,
+
+       .component_driver = {
+               .dapm_widgets = cs35l34_dapm_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(cs35l34_dapm_widgets),
+               .dapm_routes = cs35l34_audio_map,
+               .num_dapm_routes = ARRAY_SIZE(cs35l34_audio_map),
+               .controls = cs35l34_snd_controls,
+               .num_controls = ARRAY_SIZE(cs35l34_snd_controls),
+       },
+};
+
+static struct regmap_config cs35l34_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = CS35L34_MAX_REGISTER,
+       .reg_defaults = cs35l34_reg,
+       .num_reg_defaults = ARRAY_SIZE(cs35l34_reg),
+       .volatile_reg = cs35l34_volatile_register,
+       .readable_reg = cs35l34_readable_register,
+       .precious_reg = cs35l34_precious_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs35l34_handle_of_data(struct i2c_client *i2c_client,
+                               struct cs35l34_platform_data *pdata)
+{
+       struct device_node *np = i2c_client->dev.of_node;
+       unsigned int val;
+
+       if (of_property_read_u32(np, "cirrus,boost-vtge-millivolt",
+               &val) >= 0) {
+               /* Boost Voltage has a maximum of 8V */
+               if (val > 8000 || (val < 3300 && val > 0)) {
+                       dev_err(&i2c_client->dev,
+                               "Invalid Boost Voltage %d mV\n", val);
+                       return -EINVAL;
+               }
+               if (val == 0)
+                       pdata->boost_vtge = 0; /* Use VP */
+               else
+                       pdata->boost_vtge = ((val - 3300)/100) + 1;
+       } else {
+               dev_warn(&i2c_client->dev,
+                       "Boost Voltage not specified. Using VP\n");
+       }
+
+       if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) {
+               pdata->boost_ind = val;
+       } else {
+               dev_err(&i2c_client->dev, "Inductor not specified.\n");
+               return -EINVAL;
+       }
+
+       if (of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val) >= 0) {
+               if (val > 3840 || val < 1200) {
+                       dev_err(&i2c_client->dev,
+                               "Invalid Boost Peak Current %d mA\n", val);
+                       return -EINVAL;
+               }
+               pdata->boost_peak = ((val - 1200)/80) + 1;
+       }
+
+       pdata->aif_half_drv = of_property_read_bool(np,
+               "cirrus,aif-half-drv");
+       pdata->digsft_disable = of_property_read_bool(np,
+               "cirrus,digsft-disable");
+
+       pdata->gain_zc_disable = of_property_read_bool(np,
+               "cirrus,gain-zc-disable");
+       pdata->amp_inv = of_property_read_bool(np, "cirrus,amp-inv");
+
+       if (of_property_read_u32(np, "cirrus,i2s-sdinloc", &val) >= 0)
+               pdata->i2s_sdinloc = val;
+       if (of_property_read_u32(np, "cirrus,tdm-rising-edge", &val) >= 0)
+               pdata->tdm_rising_edge = val;
+
+       return 0;
+}
+
+static irqreturn_t cs35l34_irq_thread(int irq, void *data)
+{
+       struct cs35l34_private *cs35l34 = data;
+       struct snd_soc_codec *codec = cs35l34->codec;
+       unsigned int sticky1, sticky2, sticky3, sticky4;
+       unsigned int mask1, mask2, mask3, mask4, current1;
+
+
+       /* ack the irq by reading all status registers */
+       regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_4, &sticky4);
+       regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_3, &sticky3);
+       regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_2, &sticky2);
+       regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &sticky1);
+
+       regmap_read(cs35l34->regmap, CS35L34_INT_MASK_4, &mask4);
+       regmap_read(cs35l34->regmap, CS35L34_INT_MASK_3, &mask3);
+       regmap_read(cs35l34->regmap, CS35L34_INT_MASK_2, &mask2);
+       regmap_read(cs35l34->regmap, CS35L34_INT_MASK_1, &mask1);
+
+       if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3)
+               && !(sticky4 & ~mask4))
+               return IRQ_NONE;
+
+       regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &current1);
+
+       if (sticky1 & CS35L34_CAL_ERR) {
+               dev_err(codec->dev, "Cal error\n");
+
+               /* error is no longer asserted; safe to reset */
+               if (!(current1 & CS35L34_CAL_ERR)) {
+                       dev_dbg(codec->dev, "Cal error release\n");
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_CAL_ERR_RLS, 0);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_CAL_ERR_RLS,
+                                       CS35L34_CAL_ERR_RLS);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_CAL_ERR_RLS, 0);
+                       /* note: amp will re-calibrate on next resume */
+               }
+       }
+
+       if (sticky1 & CS35L34_ALIVE_ERR)
+               dev_err(codec->dev, "Alive error\n");
+
+       if (sticky1 & CS35L34_AMP_SHORT) {
+               dev_crit(codec->dev, "Amp short error\n");
+
+               /* error is no longer asserted; safe to reset */
+               if (!(current1 & CS35L34_AMP_SHORT)) {
+                       dev_dbg(codec->dev,
+                               "Amp short error release\n");
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_SHORT_RLS, 0);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_SHORT_RLS,
+                                       CS35L34_SHORT_RLS);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_SHORT_RLS, 0);
+               }
+       }
+
+       if (sticky1 & CS35L34_OTW) {
+               dev_crit(codec->dev, "Over temperature warning\n");
+
+               /* error is no longer asserted; safe to reset */
+               if (!(current1 & CS35L34_OTW)) {
+                       dev_dbg(codec->dev,
+                               "Over temperature warning release\n");
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_OTW_RLS, 0);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_OTW_RLS,
+                                       CS35L34_OTW_RLS);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_OTW_RLS, 0);
+               }
+       }
+
+       if (sticky1 & CS35L34_OTE) {
+               dev_crit(codec->dev, "Over temperature error\n");
+
+               /* error is no longer asserted; safe to reset */
+               if (!(current1 & CS35L34_OTE)) {
+                       dev_dbg(codec->dev,
+                               "Over temperature error release\n");
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_OTE_RLS, 0);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_OTE_RLS,
+                                       CS35L34_OTE_RLS);
+                       regmap_update_bits(cs35l34->regmap,
+                                       CS35L34_PROT_RELEASE_CTL,
+                                       CS35L34_OTE_RLS, 0);
+               }
+       }
+
+       if (sticky3 & CS35L34_BST_HIGH) {
+               dev_crit(codec->dev, "VBST too high error; powering off!\n");
+               regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2,
+                               CS35L34_PDN_AMP, CS35L34_PDN_AMP);
+               regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1,
+                               CS35L34_PDN_ALL, CS35L34_PDN_ALL);
+       }
+
+       if (sticky3 & CS35L34_LBST_SHORT) {
+               dev_crit(codec->dev, "LBST short error; powering off!\n");
+               regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2,
+                               CS35L34_PDN_AMP, CS35L34_PDN_AMP);
+               regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1,
+                               CS35L34_PDN_ALL, CS35L34_PDN_ALL);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static const char * const cs35l34_core_supplies[] = {
+       "VA",
+       "VP",
+};
+
+static int cs35l34_i2c_probe(struct i2c_client *i2c_client,
+                             const struct i2c_device_id *id)
+{
+       struct cs35l34_private *cs35l34;
+       struct cs35l34_platform_data *pdata =
+               dev_get_platdata(&i2c_client->dev);
+       int i;
+       int ret;
+       unsigned int devid = 0;
+       unsigned int reg;
+
+       cs35l34 = devm_kzalloc(&i2c_client->dev,
+                              sizeof(struct cs35l34_private),
+                              GFP_KERNEL);
+       if (!cs35l34) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c_client, cs35l34);
+       cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap);
+       if (IS_ERR(cs35l34->regmap)) {
+               ret = PTR_ERR(cs35l34->regmap);
+               dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+               return ret;
+       }
+
+       cs35l34->num_core_supplies = ARRAY_SIZE(cs35l34_core_supplies);
+       for (i = 0; i < ARRAY_SIZE(cs35l34_core_supplies); i++)
+               cs35l34->core_supplies[i].supply = cs35l34_core_supplies[i];
+
+       ret = devm_regulator_bulk_get(&i2c_client->dev,
+               cs35l34->num_core_supplies,
+               cs35l34->core_supplies);
+       if (ret != 0) {
+               dev_err(&i2c_client->dev,
+                       "Failed to request core supplies %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(cs35l34->num_core_supplies,
+                                       cs35l34->core_supplies);
+       if (ret != 0) {
+               dev_err(&i2c_client->dev,
+                       "Failed to enable core supplies: %d\n", ret);
+               return ret;
+       }
+
+       if (pdata) {
+               cs35l34->pdata = *pdata;
+       } else {
+               pdata = devm_kzalloc(&i2c_client->dev,
+                               sizeof(struct cs35l34_platform_data),
+                               GFP_KERNEL);
+               if (!pdata) {
+                       dev_err(&i2c_client->dev,
+                               "could not allocate pdata\n");
+                       return -ENOMEM;
+               }
+               if (i2c_client->dev.of_node) {
+                       ret = cs35l34_handle_of_data(i2c_client, pdata);
+                       if (ret != 0)
+                               return ret;
+
+               }
+               cs35l34->pdata = *pdata;
+       }
+
+       ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
+                       cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+                       "cs35l34", cs35l34);
+       if (ret != 0)
+               dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+
+       cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+                               "reset-gpios", GPIOD_OUT_LOW);
+       if (IS_ERR(cs35l34->reset_gpio))
+               return PTR_ERR(cs35l34->reset_gpio);
+
+       gpiod_set_value_cansleep(cs35l34->reset_gpio, 1);
+
+       msleep(CS35L34_START_DELAY);
+
+       ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_AB, &reg);
+
+       devid = (reg & 0xFF) << 12;
+       ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_CD, &reg);
+       devid |= (reg & 0xFF) << 4;
+       ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_E, &reg);
+       devid |= (reg & 0xF0) >> 4;
+
+       if (devid != CS35L34_CHIP_ID) {
+               dev_err(&i2c_client->dev,
+                       "CS35l34 Device ID (%X). Expected ID %X\n",
+                       devid, CS35L34_CHIP_ID);
+               ret = -ENODEV;
+               goto err_regulator;
+       }
+
+       ret = regmap_read(cs35l34->regmap, CS35L34_REV_ID, &reg);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+               goto err_regulator;
+       }
+
+       dev_info(&i2c_client->dev,
+                "Cirrus Logic CS35l34 (%x), Revision: %02X\n", devid,
+               reg & 0xFF);
+
+       /* Unmask critical interrupts */
+       regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_1,
+                               CS35L34_M_CAL_ERR | CS35L34_M_ALIVE_ERR |
+                               CS35L34_M_AMP_SHORT | CS35L34_M_OTW |
+                               CS35L34_M_OTE, 0);
+       regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_3,
+                               CS35L34_M_BST_HIGH | CS35L34_M_LBST_SHORT, 0);
+
+       pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100);
+       pm_runtime_use_autosuspend(&i2c_client->dev);
+       pm_runtime_set_active(&i2c_client->dev);
+       pm_runtime_enable(&i2c_client->dev);
+
+       ret =  snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_dev_cs35l34, &cs35l34_dai, 1);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev,
+                       "%s: Register codec failed\n", __func__);
+               goto err_regulator;
+       }
+
+       return 0;
+
+err_regulator:
+       regulator_bulk_disable(cs35l34->num_core_supplies,
+               cs35l34->core_supplies);
+
+       return ret;
+}
+
+static int cs35l34_i2c_remove(struct i2c_client *client)
+{
+       struct cs35l34_private *cs35l34 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+
+       if (cs35l34->reset_gpio)
+               gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
+
+       pm_runtime_disable(&client->dev);
+       regulator_bulk_disable(cs35l34->num_core_supplies,
+               cs35l34->core_supplies);
+
+       return 0;
+}
+
+static int __maybe_unused cs35l34_runtime_resume(struct device *dev)
+{
+       struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regulator_bulk_enable(cs35l34->num_core_supplies,
+               cs35l34->core_supplies);
+
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable core supplies: %d\n",
+                       ret);
+               return ret;
+       }
+
+       regcache_cache_only(cs35l34->regmap, false);
+
+       gpiod_set_value_cansleep(cs35l34->reset_gpio, 1);
+       msleep(CS35L34_START_DELAY);
+
+       ret = regcache_sync(cs35l34->regmap);
+       if (ret != 0) {
+               dev_err(dev, "Failed to restore register cache\n");
+               goto err;
+       }
+       return 0;
+err:
+       regcache_cache_only(cs35l34->regmap, true);
+       regulator_bulk_disable(cs35l34->num_core_supplies,
+               cs35l34->core_supplies);
+
+       return ret;
+}
+
+static int __maybe_unused cs35l34_runtime_suspend(struct device *dev)
+{
+       struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
+
+       regcache_cache_only(cs35l34->regmap, true);
+       regcache_mark_dirty(cs35l34->regmap);
+
+       gpiod_set_value_cansleep(cs35l34->reset_gpio, 0);
+
+       regulator_bulk_disable(cs35l34->num_core_supplies,
+                       cs35l34->core_supplies);
+
+       return 0;
+}
+
+static const struct dev_pm_ops cs35l34_pm_ops = {
+       SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend,
+                          cs35l34_runtime_resume,
+                          NULL)
+};
+
+static const struct of_device_id cs35l34_of_match[] = {
+       {.compatible = "cirrus,cs35l34"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, cs35l34_of_match);
+
+static const struct i2c_device_id cs35l34_id[] = {
+       {"cs35l34", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs35l34_id);
+
+static struct i2c_driver cs35l34_i2c_driver = {
+       .driver = {
+               .name = "cs35l34",
+               .pm = &cs35l34_pm_ops,
+               .of_match_table = cs35l34_of_match,
+
+               },
+       .id_table = cs35l34_id,
+       .probe = cs35l34_i2c_probe,
+       .remove = cs35l34_i2c_remove,
+
+};
+
+static int __init cs35l34_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&cs35l34_i2c_driver);
+       if (ret != 0) {
+               pr_err("Failed to register CS35l34 I2C driver: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+module_init(cs35l34_modinit);
+
+static void __exit cs35l34_exit(void)
+{
+       i2c_del_driver(&cs35l34_i2c_driver);
+}
+module_exit(cs35l34_exit);
+
+MODULE_DESCRIPTION("ASoC CS35l34 driver");
+MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l34.h b/sound/soc/codecs/cs35l34.h
new file mode 100644 (file)
index 0000000..bcd54f1
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * cs35l34.h -- CS35L34 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Paul Handrigan <Paul.Handrigan@cirrus.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 __CS35L34_H__
+#define __CS35L34_H__
+
+#define CS35L34_CHIP_ID                        0x00035A34
+#define CS35L34_DEVID_AB               0x01    /* Device ID A & B [RO] */
+#define CS35L34_DEVID_CD               0x02    /* Device ID C & D [RO] */
+#define CS35L34_DEVID_E                        0x03    /* Device ID E [RO] */
+#define CS35L34_FAB_ID                 0x04    /* Fab ID [RO] */
+#define CS35L34_REV_ID                 0x05    /* Revision ID [RO] */
+#define CS35L34_PWRCTL1                        0x06    /* Power Ctl 1 */
+#define CS35L34_PWRCTL2                        0x07    /* Power Ctl 2 */
+#define CS35L34_PWRCTL3                        0x08    /* Power Ctl 3 */
+#define CS35L34_ADSP_CLK_CTL           0x0A    /* (ADSP) Clock Ctl */
+#define CS35L34_MCLK_CTL               0x0B    /* Master Clocking Ctl */
+#define CS35L34_AMP_INP_DRV_CTL                0x14    /* Amp Input Drive Ctl */
+#define CS35L34_AMP_DIG_VOL_CTL                0x15    /* Amplifier Dig Volume Ctl */
+#define CS35L34_AMP_DIG_VOL            0x16    /* Amplifier Dig Volume */
+#define CS35L34_AMP_ANLG_GAIN_CTL      0x17    /* Amplifier Analog Gain Ctl */
+#define CS35L34_PROTECT_CTL            0x18    /* Amp Gain - Prot Ctl Param */
+#define CS35L34_AMP_KEEP_ALIVE_CTL     0x1A    /* Amplifier Keep Alive Ctl */
+#define CS35L34_BST_CVTR_V_CTL         0x1D    /* Boost Conv Voltage Ctl */
+#define CS35L34_BST_PEAK_I             0x1E    /* Boost Conv Peak Current */
+#define CS35L34_BST_RAMP_CTL           0x20    /* Boost Conv Soft Ramp Ctl */
+#define CS35L34_BST_CONV_COEF_1                0x21    /* Boost Conv Coefficients 1 */
+#define CS35L34_BST_CONV_COEF_2                0x22    /* Boost Conv Coefficients 2 */
+#define CS35L34_BST_CONV_SLOPE_COMP    0x23    /* Boost Conv Slope Comp */
+#define CS35L34_BST_CONV_SW_FREQ       0x24    /* Boost Conv L BST SW Freq */
+#define CS35L34_CLASS_H_CTL            0x30    /* CLS H Control */
+#define CS35L34_CLASS_H_HEADRM_CTL     0x31    /* CLS H Headroom Ctl */
+#define CS35L34_CLASS_H_RELEASE_RATE   0x32    /* CLS H Release Rate */
+#define CS35L34_CLASS_H_FET_DRIVE_CTL  0x33    /* CLS H Weak FET Drive Ctl */
+#define CS35L34_CLASS_H_STATUS         0x38    /* CLS H Status */
+#define CS35L34_VPBR_CTL               0x3A    /* VPBR Ctl */
+#define CS35L34_VPBR_VOL_CTL           0x3B    /* VPBR Volume Ctl */
+#define CS35L34_VPBR_TIMING_CTL                0x3C    /* VPBR Timing Ctl */
+#define CS35L34_PRED_MAX_ATTEN_SPK_LOAD        0x40    /* PRD Max Atten / Spkr Load */
+#define CS35L34_PRED_BROWNOUT_THRESH   0x41    /* PRD Brownout Threshold */
+#define CS35L34_PRED_BROWNOUT_VOL_CTL  0x42    /* PRD Brownout Volume Ctl */
+#define CS35L34_PRED_BROWNOUT_RATE_CTL 0x43    /* PRD Brownout Rate Ctl */
+#define CS35L34_PRED_WAIT_CTL          0x44    /* PRD Wait Ctl */
+#define CS35L34_PRED_ZVP_INIT_IMP_CTL  0x46    /* PRD ZVP Initial Imp Ctl */
+#define CS35L34_PRED_MAN_SAFE_VPI_CTL  0x47    /* PRD Manual Safe VPI Ctl */
+#define CS35L34_VPBR_ATTEN_STATUS      0x4B    /* VPBR Attenuation Status */
+#define CS35L34_PRED_BRWNOUT_ATT_STATUS        0x4C    /* PRD Brownout Atten Status */
+#define CS35L34_SPKR_MON_CTL           0x4E    /* Speaker Monitoring Ctl */
+#define CS35L34_ADSP_I2S_CTL           0x50    /* ADSP I2S Ctl */
+#define CS35L34_ADSP_TDM_CTL           0x51    /* ADSP TDM Ctl */
+#define CS35L34_TDM_TX_CTL_1_VMON      0x52    /* TDM TX Ctl 1 (VMON) */
+#define CS35L34_TDM_TX_CTL_2_IMON      0x53    /* TDM TX Ctl 2 (IMON) */
+#define CS35L34_TDM_TX_CTL_3_VPMON     0x54    /* TDM TX Ctl 3 (VPMON) */
+#define CS35L34_TDM_TX_CTL_4_VBSTMON   0x55    /* TDM TX Ctl 4 (VBSTMON) */
+#define CS35L34_TDM_TX_CTL_5_FLAG1     0x56    /* TDM TX Ctl 5 (FLAG1) */
+#define CS35L34_TDM_TX_CTL_6_FLAG2     0x57    /* TDM TX Ctl 6 (FLAG2) */
+#define CS35L34_TDM_TX_SLOT_EN_1       0x5A    /* TDM TX Slot Enable */
+#define CS35L34_TDM_TX_SLOT_EN_2       0x5B    /* TDM TX Slot Enable */
+#define CS35L34_TDM_TX_SLOT_EN_3       0x5C    /* TDM TX Slot Enable */
+#define CS35L34_TDM_TX_SLOT_EN_4       0x5D    /* TDM TX Slot Enable */
+#define CS35L34_TDM_RX_CTL_1_AUDIN     0x5E    /* TDM RX Ctl 1 */
+#define CS35L34_TDM_RX_CTL_3_ALIVE     0x60    /* TDM RX Ctl 3 (ALIVE) */
+#define CS35L34_MULT_DEV_SYNCH1                0x62    /* Multidevice Synch */
+#define CS35L34_MULT_DEV_SYNCH2                0x63    /* Multidevice Synch 2 */
+#define CS35L34_PROT_RELEASE_CTL       0x64    /* Protection Release Ctl */
+#define CS35L34_DIAG_MODE_REG_LOCK     0x68    /* Diagnostic Mode Reg Lock */
+#define CS35L34_DIAG_MODE_CTL_1                0x69    /* Diagnostic Mode Ctl 1 */
+#define CS35L34_DIAG_MODE_CTL_2                0x6A    /* Diagnostic Mode Ctl 2 */
+#define CS35L34_INT_MASK_1             0x70    /* Interrupt Mask 1 */
+#define CS35L34_INT_MASK_2             0x71    /* Interrupt Mask 2 */
+#define CS35L34_INT_MASK_3             0x72    /* Interrupt Mask 3 */
+#define CS35L34_INT_MASK_4             0x73    /* Interrupt Mask 4 */
+#define CS35L34_INT_STATUS_1           0x74    /* Interrupt Status 1 */
+#define CS35L34_INT_STATUS_2           0x75    /* Interrupt Status 2 */
+#define CS35L34_INT_STATUS_3           0x76    /* Interrupt Status 3 */
+#define CS35L34_INT_STATUS_4           0x77    /* Interrupt Status 4 */
+#define CS35L34_OTP_TRIM_STATUS                0x7E    /* OTP Trim Status */
+
+#define CS35L34_MAX_REGISTER           0x7F
+#define CS35L34_REGISTER_COUNT         0x4E
+
+#define CS35L34_MCLK_5644              5644800
+#define CS35L34_MCLK_6144              6144000
+#define CS35L34_MCLK_6                 6000000
+#define CS35L34_MCLK_11289             11289600
+#define CS35L34_MCLK_12                        12000000
+#define CS35L34_MCLK_12288             12288000
+
+/* CS35L34_PWRCTL1 */
+#define CS35L34_SFT_RST                        (1 << 7)
+#define CS35L34_DISCHG_FLT             (1 << 1)
+#define CS35L34_PDN_ALL                        1
+
+/* CS35L34_PWRCTL2 */
+#define CS35L34_PDN_VMON               (1 << 7)
+#define CS35L34_PDN_IMON               (1 << 6)
+#define CS35L34_PDN_CLASSH             (1 << 5)
+#define CS35L34_PDN_VPBR               (1 << 4)
+#define CS35L34_PDN_PRED               (1 << 3)
+#define CS35L34_PDN_BST                        (1 << 2)
+#define CS35L34_PDN_AMP                        1
+
+/* CS35L34_PWRCTL3 */
+#define CS35L34_MCLK_DIS               (1 << 7)
+#define CS35L34_PDN_VBSTMON_OUT                (1 << 4)
+#define CS35L34_PDN_VMON_OUT           (1 << 3)
+/* Tristate the ADSP SDOUT when in I2C mode */
+#define CS35L34_PDN_SDOUT              (1 << 2)
+#define CS35L34_PDN_SDIN               (1 << 1)
+#define CS35L34_PDN_TDM                        1
+
+/* CS35L34_ADSP_CLK_CTL */
+#define CS35L34_ADSP_RATE              0xF
+#define CS35L34_ADSP_DRIVE             (1 << 4)
+#define CS35L34_ADSP_M_S               (1 << 7)
+
+/* CS35L34_MCLK_CTL */
+#define CS35L34_MCLK_DIV               (1 << 4)
+#define CS35L34_MCLK_RATE_MASK         0x7
+#define CS35L34_MCLK_RATE_6P1440       0x2
+#define CS35L34_MCLK_RATE_6P0000       0x1
+#define CS35L34_MCLK_RATE_5P6448       0x0
+#define CS35L34_MCLKDIS                        (1 << 7)
+#define CS35L34_MCLKDIV2               (1 << 6)
+#define CS35L34_SDOUT_3ST_TDM          (1 << 5)
+#define CS35L34_INT_FS_RATE            (1 << 4)
+#define CS35L34_ADSP_FS                        0xF
+
+/* CS35L34_AMP_INP_DRV_CTL */
+#define CS35L34_DRV_STR_SRC            (1 << 1)
+#define CS35L34_DRV_STR                        1
+
+/* CS35L34_AMP_DIG_VOL_CTL */
+#define CS35L34_AMP_DSR_RATE_MASK      0xF0
+#define CS35L34_AMP_DSR_RATE_SHIFT     (1 << 4)
+#define CS35L34_NOTCH_DIS              (1 << 3)
+#define CS35L34_AMP_DIGSFT             (1 << 1)
+#define CS35L34_INV                    1
+
+/* CS35L34_PROTECT_CTL */
+#define CS35L34_OTW_ATTN_MASK          0xC
+#define CS35L34_OTW_THRD_MASK          0x3
+#define CS35L34_MUTE                   (1 << 5)
+#define CS35L34_GAIN_ZC                        (1 << 4)
+#define CS35L34_GAIN_ZC_MASK           0x10
+#define CS35L34_GAIN_ZC_SHIFT          4
+
+/* CS35L34_AMP_KEEP_ALIVE_CTL */
+#define CS35L34_ALIVE_WD_DIS           (1 << 2)
+
+/* CS35L34_BST_CVTR_V_CTL */
+#define CS35L34_BST_CVTL_MASK          0x3F
+
+/* CS35L34_BST_PEAK_I */
+#define CS35L34_BST_PEAK_MASK          0x3F
+
+/* CS35L34_ADSP_I2S_CTL */
+#define CS35L34_I2S_LOC_MASK           0xC
+#define CS35L34_I2S_LOC_SHIFT          2
+
+/* CS35L34_MULT_DEV_SYNCH2 */
+#define CS35L34_SYNC2_MASK             0xF
+
+/* CS35L34_PROT_RELEASE_CTL */
+#define CS35L34_CAL_ERR_RLS            (1 << 7)
+#define CS35L34_SHORT_RLS              (1 << 2)
+#define CS35L34_OTW_RLS                        (1 << 1)
+#define CS35L34_OTE_RLS                        1
+
+/* CS35L34_INT_MASK_1 */
+#define CS35L34_M_CAL_ERR_SHIFT                7
+#define CS35L34_M_CAL_ERR              (1 << CS35L34_M_CAL_ERR_SHIFT)
+#define CS35L34_M_ALIVE_ERR_SHIFT      5
+#define CS35L34_M_ALIVE_ERR            (1 << CS35L34_M_ALIVE_ERR_SHIFT)
+#define CS35L34_M_ADSP_CLK_SHIFT       4
+#define CS35L34_M_ADSP_CLK_ERR         (1 << CS35L34_M_ADSP_CLK_SHIFT)
+#define CS35L34_M_MCLK_SHIFT           3
+#define CS35L34_M_MCLK_ERR             (1 << CS35L34_M_MCLK_SHIFT)
+#define CS35L34_M_AMP_SHORT_SHIFT      2
+#define CS35L34_M_AMP_SHORT            (1 << CS35L34_M_AMP_SHORT_SHIFT)
+#define CS35L34_M_OTW_SHIFT            1
+#define CS35L34_M_OTW                  (1 << CS35L34_M_OTW_SHIFT)
+#define CS35L34_M_OTE_SHIFT            0
+#define CS35L34_M_OTE                  (1 << CS35L34_M_OTE_SHIFT)
+
+/* CS35L34_INT_MASK_2 */
+#define CS35L34_M_PDN_DONE_SHIFT       4
+#define CS35L34_M_PDN_DONE             (1 << CS35L34_M_PDN_DONE_SHIFT)
+#define CS35L34_M_PRED_SHIFT           3
+#define CS35L34_M_PRED_ERR             (1 << CS35L34_M_PRED_SHIFT)
+#define CS35L34_M_PRED_CLR_SHIFT       2
+#define CS35L34_M_PRED_CLR             (1 << CS35L34_M_PRED_CLR_SHIFT)
+#define CS35L34_M_VPBR_SHIFT           1
+#define CS35L34_M_VPBR_ERR             (1 << CS35L34_M_VPBR_SHIFT)
+#define CS35L34_M_VPBR_CLR_SHIFT       0
+#define CS35L34_M_VPBR_CLR             (1 << CS35L34_M_VPBR_CLR_SHIFT)
+
+/* CS35L34_INT_MASK_3 */
+#define CS35L34_M_BST_HIGH_SHIFT       4
+#define CS35L34_M_BST_HIGH             (1 << CS35L34_M_BST_HIGH_SHIFT)
+#define CS35L34_M_BST_HIGH_FLAG_SHIFT  3
+#define CS35L34_M_BST_HIGH_FLAG                (1 << CS35L34_M_BST_HIGH_FLAG_SHIFT)
+#define CS35L34_M_BST_IPK_FLAG_SHIFT   2
+#define CS35L34_M_BST_IPK_FLAG         (1 << CS35L34_M_BST_IPK_FLAG_SHIFT)
+#define CS35L34_M_LBST_SHORT_SHIFT     0
+#define CS35L34_M_LBST_SHORT           (1 << CS35L34_M_LBST_SHORT_SHIFT)
+
+/* CS35L34_INT_MASK_4 */
+#define CS35L34_M_VMON_OVFL_SHIFT      3
+#define CS35L34_M_VMON_OVFL            (1 << CS35L34_M_VMON_OVFL_SHIFT)
+#define CS35L34_M_IMON_OVFL_SHIFT      2
+#define CS35L34_M_IMON_OVFL            (1 << CS35L34_M_IMON_OVFL_SHIFT)
+#define CS35L34_M_VPMON_OVFL_SHIFT     1
+#define CS35L34_M_VPMON_OVFL           (1 << CS35L34_M_VPMON_OVFL_SHIFT)
+#define CS35L34_M_VBSTMON_OVFL_SHIFT   1
+#define CS35L34_M_VBSTMON_OVFL         (1 << CS35L34_M_VBSTMON_OVFL_SHIFT)
+
+/* CS35L34_INT_1 */
+#define CS35L34_CAL_ERR                        (1 << CS35L34_M_CAL_ERR_SHIFT)
+#define CS35L34_ALIVE_ERR              (1 << CS35L34_M_ALIVE_ERR_SHIFT)
+#define CS35L34_M_ADSP_CLK_ERR         (1 << CS35L34_M_ADSP_CLK_SHIFT)
+#define CS35L34_MCLK_ERR               (1 << CS35L34_M_MCLK_SHIFT)
+#define CS35L34_AMP_SHORT              (1 << CS35L34_M_AMP_SHORT_SHIFT)
+#define CS35L34_OTW                    (1 << CS35L34_M_OTW_SHIFT)
+#define CS35L34_OTE                    (1 << CS35L34_M_OTE_SHIFT)
+
+/* CS35L34_INT_2 */
+#define CS35L34_PDN_DONE               (1 << CS35L34_M_PDN_DONE_SHIFT)
+#define CS35L34_PRED_ERR               (1 << CS35L34_M_PRED_SHIFT)
+#define CS35L34_PRED_CLR               (1 << CS35L34_M_PRED_CLR_SHIFT)
+#define CS35L34_VPBR_ERR               (1 << CS35L34_M_VPBR_SHIFT)
+#define CS35L34_VPBR_CLR               (1 << CS35L34_M_VPBR_CLR_SHIFT)
+
+/* CS35L34_INT_3 */
+#define CS35L34_BST_HIGH               (1 << CS35L34_M_BST_HIGH_SHIFT)
+#define CS35L34_BST_HIGH_FLAG          (1 << CS35L34_M_BST_HIGH_FLAG_SHIFT)
+#define CS35L34_BST_IPK_FLAG           (1 << CS35L34_M_BST_IPK_FLAG_SHIFT)
+#define CS35L34_LBST_SHORT             (1 << CS35L34_M_LBST_SHORT_SHIFT)
+
+/* CS35L34_INT_4 */
+#define CS35L34_VMON_OVFL              (1 << CS35L34_M_VMON_OVFL_SHIFT)
+#define CS35L34_IMON_OVFL              (1 << CS35L34_M_IMON_OVFL_SHIFT)
+#define CS35L34_VPMON_OVFL             (1 << CS35L34_M_VPMON_OVFL_SHIFT)
+#define CS35L34_VBSTMON_OVFL           (1 << CS35L34_M_VBSTMON_OVFL_SHIFT)
+
+/* CS35L34_{RX,TX}_X */
+#define CS35L34_X_STATE_SHIFT          7
+#define CS35L34_X_STATE                        (1 << CS35L34_X_STATE_SHIFT)
+#define CS35L34_X_LOC_SHIFT            0
+#define CS35L34_X_LOC                  (0x1F << CS35L34_X_LOC_SHIFT)
+
+#define CS35L34_RATES (SNDRV_PCM_RATE_48000 | \
+                       SNDRV_PCM_RATE_44100 | \
+                       SNDRV_PCM_RATE_32000)
+#define CS35L34_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | \
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+#endif
index 18baea2f7d654528cf52617bfb0c58fc2e3b8efe..84f86745c30e93cd746935113f3c0aa08fd4021e 100644 (file)
@@ -148,11 +148,11 @@ SND_SOC_DAPM_OUTPUT("AOUTR"),
 };
 
 static const struct snd_soc_dapm_route cs4270_dapm_routes[] = {
-       { "Capture", NULL, "AINA" },
-       { "Capture", NULL, "AINB" },
+       { "Capture", NULL, "AINL" },
+       { "Capture", NULL, "AINR" },
 
-       { "AOUTA", NULL, "Playback" },
-       { "AOUTB", NULL, "Playback" },
+       { "AOUTL", NULL, "Playback" },
+       { "AOUTR", NULL, "Playback" },
 };
 
 /**
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
new file mode 100644 (file)
index 0000000..55e4520
--- /dev/null
@@ -0,0 +1,1986 @@
+/*
+ * cs42l42.c -- CS42L42 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.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/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.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 <dt-bindings/sound/cs42l42.h>
+
+#include "cs42l42.h"
+
+static const struct reg_default cs42l42_reg_defaults[] = {
+       { CS42L42_FRZ_CTL,                      0x00 },
+       { CS42L42_SRC_CTL,                      0x10 },
+       { CS42L42_MCLK_STATUS,                  0x02 },
+       { CS42L42_MCLK_CTL,                     0x02 },
+       { CS42L42_SFTRAMP_RATE,                 0xA4 },
+       { CS42L42_I2C_DEBOUNCE,                 0x88 },
+       { CS42L42_I2C_STRETCH,                  0x03 },
+       { CS42L42_I2C_TIMEOUT,                  0xB7 },
+       { CS42L42_PWR_CTL1,                     0xFF },
+       { CS42L42_PWR_CTL2,                     0x84 },
+       { CS42L42_PWR_CTL3,                     0x20 },
+       { CS42L42_RSENSE_CTL1,                  0x40 },
+       { CS42L42_RSENSE_CTL2,                  0x00 },
+       { CS42L42_OSC_SWITCH,                   0x00 },
+       { CS42L42_OSC_SWITCH_STATUS,            0x05 },
+       { CS42L42_RSENSE_CTL3,                  0x1B },
+       { CS42L42_TSENSE_CTL,                   0x1B },
+       { CS42L42_TSRS_INT_DISABLE,             0x00 },
+       { CS42L42_TRSENSE_STATUS,               0x00 },
+       { CS42L42_HSDET_CTL1,                   0x77 },
+       { CS42L42_HSDET_CTL2,                   0x00 },
+       { CS42L42_HS_SWITCH_CTL,                0xF3 },
+       { CS42L42_HS_DET_STATUS,                0x00 },
+       { CS42L42_HS_CLAMP_DISABLE,             0x00 },
+       { CS42L42_MCLK_SRC_SEL,                 0x00 },
+       { CS42L42_SPDIF_CLK_CFG,                0x00 },
+       { CS42L42_FSYNC_PW_LOWER,               0x00 },
+       { CS42L42_FSYNC_PW_UPPER,               0x00 },
+       { CS42L42_FSYNC_P_LOWER,                0xF9 },
+       { CS42L42_FSYNC_P_UPPER,                0x00 },
+       { CS42L42_ASP_CLK_CFG,                  0x00 },
+       { CS42L42_ASP_FRM_CFG,                  0x10 },
+       { CS42L42_FS_RATE_EN,                   0x00 },
+       { CS42L42_IN_ASRC_CLK,                  0x00 },
+       { CS42L42_OUT_ASRC_CLK,                 0x00 },
+       { CS42L42_PLL_DIV_CFG1,                 0x00 },
+       { CS42L42_ADC_OVFL_STATUS,              0x00 },
+       { CS42L42_MIXER_STATUS,                 0x00 },
+       { CS42L42_SRC_STATUS,                   0x00 },
+       { CS42L42_ASP_RX_STATUS,                0x00 },
+       { CS42L42_ASP_TX_STATUS,                0x00 },
+       { CS42L42_CODEC_STATUS,                 0x00 },
+       { CS42L42_DET_INT_STATUS1,              0x00 },
+       { CS42L42_DET_INT_STATUS2,              0x00 },
+       { CS42L42_SRCPL_INT_STATUS,             0x00 },
+       { CS42L42_VPMON_STATUS,                 0x00 },
+       { CS42L42_PLL_LOCK_STATUS,              0x00 },
+       { CS42L42_TSRS_PLUG_STATUS,             0x00 },
+       { CS42L42_ADC_OVFL_INT_MASK,            0x01 },
+       { CS42L42_MIXER_INT_MASK,               0x0F },
+       { CS42L42_SRC_INT_MASK,                 0x0F },
+       { CS42L42_ASP_RX_INT_MASK,              0x1F },
+       { CS42L42_ASP_TX_INT_MASK,              0x0F },
+       { CS42L42_CODEC_INT_MASK,               0x03 },
+       { CS42L42_SRCPL_INT_MASK,               0xFF },
+       { CS42L42_VPMON_INT_MASK,               0x01 },
+       { CS42L42_PLL_LOCK_INT_MASK,            0x01 },
+       { CS42L42_TSRS_PLUG_INT_MASK,           0x0F },
+       { CS42L42_PLL_CTL1,                     0x00 },
+       { CS42L42_PLL_DIV_FRAC0,                0x00 },
+       { CS42L42_PLL_DIV_FRAC1,                0x00 },
+       { CS42L42_PLL_DIV_FRAC2,                0x00 },
+       { CS42L42_PLL_DIV_INT,                  0x40 },
+       { CS42L42_PLL_CTL3,                     0x10 },
+       { CS42L42_PLL_CAL_RATIO,                0x80 },
+       { CS42L42_PLL_CTL4,                     0x03 },
+       { CS42L42_LOAD_DET_RCSTAT,              0x00 },
+       { CS42L42_LOAD_DET_DONE,                0x00 },
+       { CS42L42_LOAD_DET_EN,                  0x00 },
+       { CS42L42_HSBIAS_SC_AUTOCTL,            0x03 },
+       { CS42L42_WAKE_CTL,                     0xC0 },
+       { CS42L42_ADC_DISABLE_MUTE,             0x00 },
+       { CS42L42_TIPSENSE_CTL,                 0x02 },
+       { CS42L42_MISC_DET_CTL,                 0x03 },
+       { CS42L42_MIC_DET_CTL1,                 0x1F },
+       { CS42L42_MIC_DET_CTL2,                 0x2F },
+       { CS42L42_DET_STATUS1,                  0x00 },
+       { CS42L42_DET_STATUS2,                  0x00 },
+       { CS42L42_DET_INT1_MASK,                0xE0 },
+       { CS42L42_DET_INT2_MASK,                0xFF },
+       { CS42L42_HS_BIAS_CTL,                  0xC2 },
+       { CS42L42_ADC_CTL,                      0x00 },
+       { CS42L42_ADC_VOLUME,                   0x00 },
+       { CS42L42_ADC_WNF_HPF_CTL,              0x71 },
+       { CS42L42_DAC_CTL1,                     0x00 },
+       { CS42L42_DAC_CTL2,                     0x02 },
+       { CS42L42_HP_CTL,                       0x0D },
+       { CS42L42_CLASSH_CTL,                   0x07 },
+       { CS42L42_MIXER_CHA_VOL,                0x3F },
+       { CS42L42_MIXER_ADC_VOL,                0x3F },
+       { CS42L42_MIXER_CHB_VOL,                0x3F },
+       { CS42L42_EQ_COEF_IN0,                  0x22 },
+       { CS42L42_EQ_COEF_IN1,                  0x00 },
+       { CS42L42_EQ_COEF_IN2,                  0x00 },
+       { CS42L42_EQ_COEF_IN3,                  0x00 },
+       { CS42L42_EQ_COEF_RW,                   0x00 },
+       { CS42L42_EQ_COEF_OUT0,                 0x00 },
+       { CS42L42_EQ_COEF_OUT1,                 0x00 },
+       { CS42L42_EQ_COEF_OUT2,                 0x00 },
+       { CS42L42_EQ_COEF_OUT3,                 0x00 },
+       { CS42L42_EQ_INIT_STAT,                 0x00 },
+       { CS42L42_EQ_START_FILT,                0x00 },
+       { CS42L42_EQ_MUTE_CTL,                  0x00 },
+       { CS42L42_SP_RX_CH_SEL,                 0x04 },
+       { CS42L42_SP_RX_ISOC_CTL,               0x04 },
+       { CS42L42_SP_RX_FS,                     0x8C },
+       { CS42l42_SPDIF_CH_SEL,                 0x0E },
+       { CS42L42_SP_TX_ISOC_CTL,               0x04 },
+       { CS42L42_SP_TX_FS,                     0xCC },
+       { CS42L42_SPDIF_SW_CTL1,                0x3F },
+       { CS42L42_SRC_SDIN_FS,                  0x40 },
+       { CS42L42_SRC_SDOUT_FS,                 0x40 },
+       { CS42L42_SPDIF_CTL1,                   0x01 },
+       { CS42L42_SPDIF_CTL2,                   0x00 },
+       { CS42L42_SPDIF_CTL3,                   0x00 },
+       { CS42L42_SPDIF_CTL4,                   0x42 },
+       { CS42L42_ASP_TX_SZ_EN,                 0x00 },
+       { CS42L42_ASP_TX_CH_EN,                 0x00 },
+       { CS42L42_ASP_TX_CH_AP_RES,             0x0F },
+       { CS42L42_ASP_TX_CH1_BIT_MSB,           0x00 },
+       { CS42L42_ASP_TX_CH1_BIT_LSB,           0x00 },
+       { CS42L42_ASP_TX_HIZ_DLY_CFG,           0x00 },
+       { CS42L42_ASP_TX_CH2_BIT_MSB,           0x00 },
+       { CS42L42_ASP_TX_CH2_BIT_LSB,           0x00 },
+       { CS42L42_ASP_RX_DAI0_EN,               0x00 },
+       { CS42L42_ASP_RX_DAI0_CH1_AP_RES,       0x03 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB,      0x00 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB,      0x00 },
+       { CS42L42_ASP_RX_DAI0_CH2_AP_RES,       0x03 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB,      0x00 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB,      0x00 },
+       { CS42L42_ASP_RX_DAI0_CH3_AP_RES,       0x03 },
+       { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB,      0x00 },
+       { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB,      0x00 },
+       { CS42L42_ASP_RX_DAI0_CH4_AP_RES,       0x03 },
+       { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB,      0x00 },
+       { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB,      0x00 },
+       { CS42L42_ASP_RX_DAI1_CH1_AP_RES,       0x03 },
+       { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB,      0x00 },
+       { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB,      0x00 },
+       { CS42L42_ASP_RX_DAI1_CH2_AP_RES,       0x03 },
+       { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB,      0x00 },
+       { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB,      0x00 },
+       { CS42L42_SUB_REVID,                    0x03 },
+};
+
+static bool cs42l42_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L42_PAGE_REGISTER:
+       case CS42L42_DEVID_AB:
+       case CS42L42_DEVID_CD:
+       case CS42L42_DEVID_E:
+       case CS42L42_FABID:
+       case CS42L42_REVID:
+       case CS42L42_FRZ_CTL:
+       case CS42L42_SRC_CTL:
+       case CS42L42_MCLK_STATUS:
+       case CS42L42_MCLK_CTL:
+       case CS42L42_SFTRAMP_RATE:
+       case CS42L42_I2C_DEBOUNCE:
+       case CS42L42_I2C_STRETCH:
+       case CS42L42_I2C_TIMEOUT:
+       case CS42L42_PWR_CTL1:
+       case CS42L42_PWR_CTL2:
+       case CS42L42_PWR_CTL3:
+       case CS42L42_RSENSE_CTL1:
+       case CS42L42_RSENSE_CTL2:
+       case CS42L42_OSC_SWITCH:
+       case CS42L42_OSC_SWITCH_STATUS:
+       case CS42L42_RSENSE_CTL3:
+       case CS42L42_TSENSE_CTL:
+       case CS42L42_TSRS_INT_DISABLE:
+       case CS42L42_TRSENSE_STATUS:
+       case CS42L42_HSDET_CTL1:
+       case CS42L42_HSDET_CTL2:
+       case CS42L42_HS_SWITCH_CTL:
+       case CS42L42_HS_DET_STATUS:
+       case CS42L42_HS_CLAMP_DISABLE:
+       case CS42L42_MCLK_SRC_SEL:
+       case CS42L42_SPDIF_CLK_CFG:
+       case CS42L42_FSYNC_PW_LOWER:
+       case CS42L42_FSYNC_PW_UPPER:
+       case CS42L42_FSYNC_P_LOWER:
+       case CS42L42_FSYNC_P_UPPER:
+       case CS42L42_ASP_CLK_CFG:
+       case CS42L42_ASP_FRM_CFG:
+       case CS42L42_FS_RATE_EN:
+       case CS42L42_IN_ASRC_CLK:
+       case CS42L42_OUT_ASRC_CLK:
+       case CS42L42_PLL_DIV_CFG1:
+       case CS42L42_ADC_OVFL_STATUS:
+       case CS42L42_MIXER_STATUS:
+       case CS42L42_SRC_STATUS:
+       case CS42L42_ASP_RX_STATUS:
+       case CS42L42_ASP_TX_STATUS:
+       case CS42L42_CODEC_STATUS:
+       case CS42L42_DET_INT_STATUS1:
+       case CS42L42_DET_INT_STATUS2:
+       case CS42L42_SRCPL_INT_STATUS:
+       case CS42L42_VPMON_STATUS:
+       case CS42L42_PLL_LOCK_STATUS:
+       case CS42L42_TSRS_PLUG_STATUS:
+       case CS42L42_ADC_OVFL_INT_MASK:
+       case CS42L42_MIXER_INT_MASK:
+       case CS42L42_SRC_INT_MASK:
+       case CS42L42_ASP_RX_INT_MASK:
+       case CS42L42_ASP_TX_INT_MASK:
+       case CS42L42_CODEC_INT_MASK:
+       case CS42L42_SRCPL_INT_MASK:
+       case CS42L42_VPMON_INT_MASK:
+       case CS42L42_PLL_LOCK_INT_MASK:
+       case CS42L42_TSRS_PLUG_INT_MASK:
+       case CS42L42_PLL_CTL1:
+       case CS42L42_PLL_DIV_FRAC0:
+       case CS42L42_PLL_DIV_FRAC1:
+       case CS42L42_PLL_DIV_FRAC2:
+       case CS42L42_PLL_DIV_INT:
+       case CS42L42_PLL_CTL3:
+       case CS42L42_PLL_CAL_RATIO:
+       case CS42L42_PLL_CTL4:
+       case CS42L42_LOAD_DET_RCSTAT:
+       case CS42L42_LOAD_DET_DONE:
+       case CS42L42_LOAD_DET_EN:
+       case CS42L42_HSBIAS_SC_AUTOCTL:
+       case CS42L42_WAKE_CTL:
+       case CS42L42_ADC_DISABLE_MUTE:
+       case CS42L42_TIPSENSE_CTL:
+       case CS42L42_MISC_DET_CTL:
+       case CS42L42_MIC_DET_CTL1:
+       case CS42L42_MIC_DET_CTL2:
+       case CS42L42_DET_STATUS1:
+       case CS42L42_DET_STATUS2:
+       case CS42L42_DET_INT1_MASK:
+       case CS42L42_DET_INT2_MASK:
+       case CS42L42_HS_BIAS_CTL:
+       case CS42L42_ADC_CTL:
+       case CS42L42_ADC_VOLUME:
+       case CS42L42_ADC_WNF_HPF_CTL:
+       case CS42L42_DAC_CTL1:
+       case CS42L42_DAC_CTL2:
+       case CS42L42_HP_CTL:
+       case CS42L42_CLASSH_CTL:
+       case CS42L42_MIXER_CHA_VOL:
+       case CS42L42_MIXER_ADC_VOL:
+       case CS42L42_MIXER_CHB_VOL:
+       case CS42L42_EQ_COEF_IN0:
+       case CS42L42_EQ_COEF_IN1:
+       case CS42L42_EQ_COEF_IN2:
+       case CS42L42_EQ_COEF_IN3:
+       case CS42L42_EQ_COEF_RW:
+       case CS42L42_EQ_COEF_OUT0:
+       case CS42L42_EQ_COEF_OUT1:
+       case CS42L42_EQ_COEF_OUT2:
+       case CS42L42_EQ_COEF_OUT3:
+       case CS42L42_EQ_INIT_STAT:
+       case CS42L42_EQ_START_FILT:
+       case CS42L42_EQ_MUTE_CTL:
+       case CS42L42_SP_RX_CH_SEL:
+       case CS42L42_SP_RX_ISOC_CTL:
+       case CS42L42_SP_RX_FS:
+       case CS42l42_SPDIF_CH_SEL:
+       case CS42L42_SP_TX_ISOC_CTL:
+       case CS42L42_SP_TX_FS:
+       case CS42L42_SPDIF_SW_CTL1:
+       case CS42L42_SRC_SDIN_FS:
+       case CS42L42_SRC_SDOUT_FS:
+       case CS42L42_SPDIF_CTL1:
+       case CS42L42_SPDIF_CTL2:
+       case CS42L42_SPDIF_CTL3:
+       case CS42L42_SPDIF_CTL4:
+       case CS42L42_ASP_TX_SZ_EN:
+       case CS42L42_ASP_TX_CH_EN:
+       case CS42L42_ASP_TX_CH_AP_RES:
+       case CS42L42_ASP_TX_CH1_BIT_MSB:
+       case CS42L42_ASP_TX_CH1_BIT_LSB:
+       case CS42L42_ASP_TX_HIZ_DLY_CFG:
+       case CS42L42_ASP_TX_CH2_BIT_MSB:
+       case CS42L42_ASP_TX_CH2_BIT_LSB:
+       case CS42L42_ASP_RX_DAI0_EN:
+       case CS42L42_ASP_RX_DAI0_CH1_AP_RES:
+       case CS42L42_ASP_RX_DAI0_CH1_BIT_MSB:
+       case CS42L42_ASP_RX_DAI0_CH1_BIT_LSB:
+       case CS42L42_ASP_RX_DAI0_CH2_AP_RES:
+       case CS42L42_ASP_RX_DAI0_CH2_BIT_MSB:
+       case CS42L42_ASP_RX_DAI0_CH2_BIT_LSB:
+       case CS42L42_ASP_RX_DAI0_CH3_AP_RES:
+       case CS42L42_ASP_RX_DAI0_CH3_BIT_MSB:
+       case CS42L42_ASP_RX_DAI0_CH3_BIT_LSB:
+       case CS42L42_ASP_RX_DAI0_CH4_AP_RES:
+       case CS42L42_ASP_RX_DAI0_CH4_BIT_MSB:
+       case CS42L42_ASP_RX_DAI0_CH4_BIT_LSB:
+       case CS42L42_ASP_RX_DAI1_CH1_AP_RES:
+       case CS42L42_ASP_RX_DAI1_CH1_BIT_MSB:
+       case CS42L42_ASP_RX_DAI1_CH1_BIT_LSB:
+       case CS42L42_ASP_RX_DAI1_CH2_AP_RES:
+       case CS42L42_ASP_RX_DAI1_CH2_BIT_MSB:
+       case CS42L42_ASP_RX_DAI1_CH2_BIT_LSB:
+       case CS42L42_SUB_REVID:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs42l42_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L42_DEVID_AB:
+       case CS42L42_DEVID_CD:
+       case CS42L42_DEVID_E:
+       case CS42L42_MCLK_STATUS:
+       case CS42L42_TRSENSE_STATUS:
+       case CS42L42_HS_DET_STATUS:
+       case CS42L42_ADC_OVFL_STATUS:
+       case CS42L42_MIXER_STATUS:
+       case CS42L42_SRC_STATUS:
+       case CS42L42_ASP_RX_STATUS:
+       case CS42L42_ASP_TX_STATUS:
+       case CS42L42_CODEC_STATUS:
+       case CS42L42_DET_INT_STATUS1:
+       case CS42L42_DET_INT_STATUS2:
+       case CS42L42_SRCPL_INT_STATUS:
+       case CS42L42_VPMON_STATUS:
+       case CS42L42_PLL_LOCK_STATUS:
+       case CS42L42_TSRS_PLUG_STATUS:
+       case CS42L42_LOAD_DET_RCSTAT:
+       case CS42L42_LOAD_DET_DONE:
+       case CS42L42_DET_STATUS1:
+       case CS42L42_DET_STATUS2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_range_cfg cs42l42_page_range = {
+       .name = "Pages",
+       .range_min = 0,
+       .range_max = CS42L42_MAX_REGISTER,
+       .selector_reg = CS42L42_PAGE_REGISTER,
+       .selector_mask = 0xff,
+       .selector_shift = 0,
+       .window_start = 0,
+       .window_len = 256,
+};
+
+static const struct regmap_config cs42l42_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .readable_reg = cs42l42_readable_register,
+       .volatile_reg = cs42l42_volatile_register,
+
+       .ranges = &cs42l42_page_range,
+       .num_ranges = 1,
+
+       .max_register = CS42L42_MAX_REGISTER,
+       .reg_defaults = cs42l42_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false);
+static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false);
+
+static const char * const cs42l42_hpf_freq_text[] = {
+       "1.86Hz", "120Hz", "235Hz", "466Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_hpf_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+                           CS42L42_ADC_HPF_CF_SHIFT,
+                           cs42l42_hpf_freq_text);
+
+static const char * const cs42l42_wnf3_freq_text[] = {
+       "160Hz", "180Hz", "200Hz", "220Hz",
+       "240Hz", "260Hz", "280Hz", "300Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_wnf3_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+                           CS42L42_ADC_WNF_CF_SHIFT,
+                           cs42l42_wnf3_freq_text);
+
+static const char * const cs42l42_wnf05_freq_text[] = {
+       "280Hz", "315Hz", "350Hz", "385Hz",
+       "420Hz", "455Hz", "490Hz", "525Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l42_wnf05_freq_enum, CS42L42_ADC_WNF_HPF_CTL,
+                           CS42L42_ADC_WNF_CF_SHIFT,
+                           cs42l42_wnf05_freq_text);
+
+static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
+       /* ADC Volume and Filter Controls */
+       SOC_SINGLE("ADC Notch Switch", CS42L42_ADC_CTL,
+                               CS42L42_ADC_NOTCH_DIS_SHIFT, true, false),
+       SOC_SINGLE("ADC Weak Force Switch", CS42L42_ADC_CTL,
+                               CS42L42_ADC_FORCE_WEAK_VCM_SHIFT, true, false),
+       SOC_SINGLE("ADC Invert Switch", CS42L42_ADC_CTL,
+                               CS42L42_ADC_INV_SHIFT, true, false),
+       SOC_SINGLE("ADC Boost Switch", CS42L42_ADC_CTL,
+                               CS42L42_ADC_DIG_BOOST_SHIFT, true, false),
+       SOC_SINGLE_SX_TLV("ADC Volume", CS42L42_ADC_VOLUME,
+                               CS42L42_ADC_VOL_SHIFT, 0xA0, 0x6C, adc_tlv),
+       SOC_SINGLE("ADC WNF Switch", CS42L42_ADC_WNF_HPF_CTL,
+                               CS42L42_ADC_WNF_EN_SHIFT, true, false),
+       SOC_SINGLE("ADC HPF Switch", CS42L42_ADC_WNF_HPF_CTL,
+                               CS42L42_ADC_HPF_EN_SHIFT, true, false),
+       SOC_ENUM("HPF Corner Freq", cs42l42_hpf_freq_enum),
+       SOC_ENUM("WNF 3dB Freq", cs42l42_wnf3_freq_enum),
+       SOC_ENUM("WNF 05dB Freq", cs42l42_wnf05_freq_enum),
+
+       /* DAC Volume and Filter Controls */
+       SOC_SINGLE("DACA Invert Switch", CS42L42_DAC_CTL1,
+                               CS42L42_DACA_INV_SHIFT, true, false),
+       SOC_SINGLE("DACB Invert Switch", CS42L42_DAC_CTL1,
+                               CS42L42_DACB_INV_SHIFT, true, false),
+       SOC_SINGLE("DAC HPF Switch", CS42L42_DAC_CTL2,
+                               CS42L42_DAC_HPF_EN_SHIFT, true, false),
+       SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL,
+                        CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT,
+                               0x3e, 1, mixer_tlv)
+};
+
+static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       if (event & SND_SOC_DAPM_POST_PMU) {
+               /* Enable the channels */
+               snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN,
+                               CS42L42_ASP_RX0_CH_EN_MASK,
+                               (CS42L42_ASP_RX0_CH1_EN |
+                               CS42L42_ASP_RX0_CH2_EN) <<
+                               CS42L42_ASP_RX0_CH_EN_SHIFT);
+
+               /* Power up */
+               snd_soc_update_bits(codec, CS42L42_PWR_CTL1,
+                       CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+                               CS42L42_HP_PDN_MASK, 0);
+       } else if (event & SND_SOC_DAPM_PRE_PMD) {
+               /* Disable the channels */
+               snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN,
+                               CS42L42_ASP_RX0_CH_EN_MASK, 0);
+
+               /* Power down */
+               snd_soc_update_bits(codec, CS42L42_PWR_CTL1,
+                       CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+                               CS42L42_HP_PDN_MASK,
+                       CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK |
+                               CS42L42_HP_PDN_MASK);
+       } else {
+               dev_err(codec->dev, "Invalid event 0x%x\n", event);
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = {
+       SND_SOC_DAPM_OUTPUT("HP"),
+       SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG,
+                                       CS42L42_ASP_SCLK_EN_SHIFT, false),
+       SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0,
+                                       0, NULL, 0, cs42l42_hpdrv_evt,
+                                       SND_SOC_DAPM_POST_PMU |
+                                       SND_SOC_DAPM_PRE_PMD)
+};
+
+static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
+       {"SDIN", NULL, "Playback"},
+       {"HPDRV", NULL, "SDIN"},
+       {"HP", NULL, "HPDRV"}
+};
+
+static int cs42l42_set_bias_level(struct snd_soc_codec *codec,
+                                       enum snd_soc_bias_level level)
+{
+       struct cs42l42_private *cs42l42 = 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 (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+                       regcache_cache_only(cs42l42->regmap, false);
+                       regcache_sync(cs42l42->regmap);
+                       ret = regulator_bulk_enable(
+                                               ARRAY_SIZE(cs42l42->supplies),
+                                               cs42l42->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable regulators: %d\n",
+                                       ret);
+                               return ret;
+                       }
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+
+               regcache_cache_only(cs42l42->regmap, true);
+               regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+                                                   cs42l42->supplies);
+               break;
+       }
+
+       return 0;
+}
+
+static int cs42l42_codec_probe(struct snd_soc_codec *codec)
+{
+       struct cs42l42_private *cs42l42 =
+               (struct cs42l42_private *)snd_soc_codec_get_drvdata(codec);
+
+       cs42l42->codec = codec;
+
+       return 0;
+}
+
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l42 = {
+       .probe = cs42l42_codec_probe,
+       .set_bias_level = cs42l42_set_bias_level,
+       .ignore_pmdown_time = true,
+
+       .component_driver = {
+               .dapm_widgets = cs42l42_dapm_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets),
+               .dapm_routes = cs42l42_audio_map,
+               .num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map),
+
+               .controls = cs42l42_snd_controls,
+               .num_controls = ARRAY_SIZE(cs42l42_snd_controls),
+       },
+};
+
+struct cs42l42_pll_params {
+       u32 sclk;
+       u8 mclk_div;
+       u8 mclk_src_sel;
+       u8 sclk_prediv;
+       u8 pll_div_int;
+       u32 pll_div_frac;
+       u8 pll_mode;
+       u8 pll_divout;
+       u32 mclk_int;
+       u8 pll_cal_ratio;
+};
+
+/*
+ * Common PLL Settings for given SCLK
+ * Table 4-5 from the Datasheet
+ */
+static const struct cs42l42_pll_params pll_ratio_table[] = {
+       { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 },
+       { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 },
+       { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 },
+       { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 },
+       { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 },
+       { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 },
+       { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 },
+       { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 },
+       { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 },
+       { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 },
+       { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 },
+       { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 },
+       { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 },
+       { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 },
+       { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 }
+};
+
+static int cs42l42_pll_config(struct snd_soc_codec *codec)
+{
+       struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+       int i;
+       u32 fsync;
+
+       for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
+               if (pll_ratio_table[i].sclk == cs42l42->sclk) {
+                       /* Configure the internal sample rate */
+                       snd_soc_update_bits(codec, CS42L42_MCLK_CTL,
+                                       CS42L42_INTERNAL_FS_MASK,
+                                       ((pll_ratio_table[i].mclk_int !=
+                                       12000000) &&
+                                       (pll_ratio_table[i].mclk_int !=
+                                       24000000)) <<
+                                       CS42L42_INTERNAL_FS_SHIFT);
+                       /* Set the MCLK src (PLL or SCLK) and the divide
+                        * ratio
+                        */
+                       snd_soc_update_bits(codec, CS42L42_MCLK_SRC_SEL,
+                                       CS42L42_MCLK_SRC_SEL_MASK |
+                                       CS42L42_MCLKDIV_MASK,
+                                       (pll_ratio_table[i].mclk_src_sel
+                                       << CS42L42_MCLK_SRC_SEL_SHIFT) |
+                                       (pll_ratio_table[i].mclk_div <<
+                                       CS42L42_MCLKDIV_SHIFT));
+                       /* Set up the LRCLK */
+                       fsync = cs42l42->sclk / cs42l42->srate;
+                       if (((fsync * cs42l42->srate) != cs42l42->sclk)
+                               || ((fsync % 2) != 0)) {
+                               dev_err(codec->dev,
+                                       "Unsupported sclk %d/sample rate %d\n",
+                                       cs42l42->sclk,
+                                       cs42l42->srate);
+                               return -EINVAL;
+                       }
+                       /* Set the LRCLK period */
+                       snd_soc_update_bits(codec,
+                                       CS42L42_FSYNC_P_LOWER,
+                                       CS42L42_FSYNC_PERIOD_MASK,
+                                       CS42L42_FRAC0_VAL(fsync - 1) <<
+                                       CS42L42_FSYNC_PERIOD_SHIFT);
+                       snd_soc_update_bits(codec,
+                                       CS42L42_FSYNC_P_UPPER,
+                                       CS42L42_FSYNC_PERIOD_MASK,
+                                       CS42L42_FRAC1_VAL(fsync - 1) <<
+                                       CS42L42_FSYNC_PERIOD_SHIFT);
+                       /* Set the LRCLK to 50% duty cycle */
+                       fsync = fsync / 2;
+                       snd_soc_update_bits(codec,
+                                       CS42L42_FSYNC_PW_LOWER,
+                                       CS42L42_FSYNC_PULSE_WIDTH_MASK,
+                                       CS42L42_FRAC0_VAL(fsync - 1) <<
+                                       CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+                       snd_soc_update_bits(codec,
+                                       CS42L42_FSYNC_PW_UPPER,
+                                       CS42L42_FSYNC_PULSE_WIDTH_MASK,
+                                       CS42L42_FRAC1_VAL(fsync - 1) <<
+                                       CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
+                       snd_soc_update_bits(codec,
+                                       CS42L42_ASP_FRM_CFG,
+                                       CS42L42_ASP_5050_MASK,
+                                       CS42L42_ASP_5050_MASK);
+                       /* Set the frame delay to 1.0 SCLK clocks */
+                       snd_soc_update_bits(codec, CS42L42_ASP_FRM_CFG,
+                                       CS42L42_ASP_FSD_MASK,
+                                       CS42L42_ASP_FSD_1_0 <<
+                                       CS42L42_ASP_FSD_SHIFT);
+                       /* Set the sample rates (96k or lower) */
+                       snd_soc_update_bits(codec, CS42L42_FS_RATE_EN,
+                                       CS42L42_FS_EN_MASK,
+                                       (CS42L42_FS_EN_IASRC_96K |
+                                       CS42L42_FS_EN_OASRC_96K) <<
+                                       CS42L42_FS_EN_SHIFT);
+                       /* Set the input/output internal MCLK clock ~12 MHz */
+                       snd_soc_update_bits(codec, CS42L42_IN_ASRC_CLK,
+                                       CS42L42_CLK_IASRC_SEL_MASK,
+                                       CS42L42_CLK_IASRC_SEL_12 <<
+                                       CS42L42_CLK_IASRC_SEL_SHIFT);
+                       snd_soc_update_bits(codec,
+                                       CS42L42_OUT_ASRC_CLK,
+                                       CS42L42_CLK_OASRC_SEL_MASK,
+                                       CS42L42_CLK_OASRC_SEL_12 <<
+                                       CS42L42_CLK_OASRC_SEL_SHIFT);
+                       /* channel 1 on low LRCLK, 32 bit */
+                       snd_soc_update_bits(codec,
+                                       CS42L42_ASP_RX_DAI0_CH1_AP_RES,
+                                       CS42L42_ASP_RX_CH_AP_MASK |
+                                       CS42L42_ASP_RX_CH_RES_MASK,
+                                       (CS42L42_ASP_RX_CH_AP_LOW <<
+                                       CS42L42_ASP_RX_CH_AP_SHIFT) |
+                                       (CS42L42_ASP_RX_CH_RES_32 <<
+                                       CS42L42_ASP_RX_CH_RES_SHIFT));
+                       /* Channel 2 on high LRCLK, 32 bit */
+                       snd_soc_update_bits(codec,
+                                       CS42L42_ASP_RX_DAI0_CH2_AP_RES,
+                                       CS42L42_ASP_RX_CH_AP_MASK |
+                                       CS42L42_ASP_RX_CH_RES_MASK,
+                                       (CS42L42_ASP_RX_CH_AP_HI <<
+                                       CS42L42_ASP_RX_CH_AP_SHIFT) |
+                                       (CS42L42_ASP_RX_CH_RES_32 <<
+                                       CS42L42_ASP_RX_CH_RES_SHIFT));
+                       if (pll_ratio_table[i].mclk_src_sel == 0) {
+                               /* Pass the clock straight through */
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_CTL1,
+                                       CS42L42_PLL_START_MASK, 0);
+                       } else {
+                               /* Configure PLL per table 4-5 */
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_DIV_CFG1,
+                                       CS42L42_SCLK_PREDIV_MASK,
+                                       pll_ratio_table[i].sclk_prediv
+                                       << CS42L42_SCLK_PREDIV_SHIFT);
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_DIV_INT,
+                                       CS42L42_PLL_DIV_INT_MASK,
+                                       pll_ratio_table[i].pll_div_int
+                                       << CS42L42_PLL_DIV_INT_SHIFT);
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_DIV_FRAC0,
+                                       CS42L42_PLL_DIV_FRAC_MASK,
+                                       CS42L42_FRAC0_VAL(
+                                       pll_ratio_table[i].pll_div_frac)
+                                       << CS42L42_PLL_DIV_FRAC_SHIFT);
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_DIV_FRAC1,
+                                       CS42L42_PLL_DIV_FRAC_MASK,
+                                       CS42L42_FRAC1_VAL(
+                                       pll_ratio_table[i].pll_div_frac)
+                                       << CS42L42_PLL_DIV_FRAC_SHIFT);
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_DIV_FRAC2,
+                                       CS42L42_PLL_DIV_FRAC_MASK,
+                                       CS42L42_FRAC2_VAL(
+                                       pll_ratio_table[i].pll_div_frac)
+                                       << CS42L42_PLL_DIV_FRAC_SHIFT);
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_CTL4,
+                                       CS42L42_PLL_MODE_MASK,
+                                       pll_ratio_table[i].pll_mode
+                                       << CS42L42_PLL_MODE_SHIFT);
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_CTL3,
+                                       CS42L42_PLL_DIVOUT_MASK,
+                                       pll_ratio_table[i].pll_divout
+                                       << CS42L42_PLL_DIVOUT_SHIFT);
+                               snd_soc_update_bits(codec,
+                                       CS42L42_PLL_CAL_RATIO,
+                                       CS42L42_PLL_CAL_RATIO_MASK,
+                                       pll_ratio_table[i].pll_cal_ratio
+                                       << CS42L42_PLL_CAL_RATIO_SHIFT);
+                       }
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u32 asp_cfg_val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFM:
+               asp_cfg_val |= CS42L42_ASP_MASTER_MODE <<
+                               CS42L42_ASP_MODE_SHIFT;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               asp_cfg_val |= CS42L42_ASP_SLAVE_MODE <<
+                               CS42L42_ASP_MODE_SHIFT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Bitclock/frame inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               asp_cfg_val |= CS42L42_ASP_POL_INV <<
+                               CS42L42_ASP_LCPOL_IN_SHIFT;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               asp_cfg_val |= CS42L42_ASP_POL_INV <<
+                               CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               asp_cfg_val |= CS42L42_ASP_POL_INV <<
+                               CS42L42_ASP_LCPOL_IN_SHIFT;
+               asp_cfg_val |= CS42L42_ASP_POL_INV <<
+                               CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
+               break;
+       }
+
+       snd_soc_update_bits(codec, CS42L42_ASP_CLK_CFG,
+                               CS42L42_ASP_MODE_MASK |
+                               CS42L42_ASP_SCPOL_IN_DAC_MASK |
+                               CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val);
+
+       return 0;
+}
+
+static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+       int retval;
+
+       cs42l42->srate = params_rate(params);
+       cs42l42->swidth = params_width(params);
+
+       retval = cs42l42_pll_config(codec);
+
+       return retval;
+}
+
+static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec);
+
+       cs42l42->sclk = freq;
+
+       return 0;
+}
+
+static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int regval;
+       u8 fullScaleVol;
+
+       if (mute) {
+               /* Mark SCLK as not present to turn on the internal
+                * oscillator.
+                */
+               snd_soc_update_bits(codec, CS42L42_OSC_SWITCH,
+                                               CS42L42_SCLK_PRESENT_MASK, 0);
+
+               snd_soc_update_bits(codec, CS42L42_PLL_CTL1,
+                               CS42L42_PLL_START_MASK,
+                               0 << CS42L42_PLL_START_SHIFT);
+
+               /* Mute the headphone */
+               snd_soc_update_bits(codec, CS42L42_HP_CTL,
+                               CS42L42_HP_ANA_AMUTE_MASK |
+                               CS42L42_HP_ANA_BMUTE_MASK,
+                               CS42L42_HP_ANA_AMUTE_MASK |
+                               CS42L42_HP_ANA_BMUTE_MASK);
+       } else {
+               snd_soc_update_bits(codec, CS42L42_PLL_CTL1,
+                               CS42L42_PLL_START_MASK,
+                               1 << CS42L42_PLL_START_SHIFT);
+               /* Read the headphone load */
+               regval = snd_soc_read(codec, CS42L42_LOAD_DET_RCSTAT);
+               if (((regval & CS42L42_RLA_STAT_MASK) >>
+                       CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) {
+                       fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
+               } else {
+                       fullScaleVol = 0;
+               }
+
+               /* Un-mute the headphone, set the full scale volume flag */
+               snd_soc_update_bits(codec, CS42L42_HP_CTL,
+                               CS42L42_HP_ANA_AMUTE_MASK |
+                               CS42L42_HP_ANA_BMUTE_MASK |
+                               CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
+
+               /* Mark SCLK as present, turn off internal oscillator */
+               snd_soc_update_bits(codec, CS42L42_OSC_SWITCH,
+                               CS42L42_SCLK_PRESENT_MASK,
+                               CS42L42_SCLK_PRESENT_MASK);
+       }
+
+       return 0;
+}
+
+#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static struct snd_soc_dai_ops cs42l42_ops = {
+       .hw_params      = cs42l42_pcm_hw_params,
+       .set_fmt        = cs42l42_set_dai_fmt,
+       .set_sysclk     = cs42l42_set_sysclk,
+       .digital_mute = cs42l42_digital_mute
+};
+
+static struct snd_soc_dai_driver cs42l42_dai = {
+               .name = "cs42l42",
+               .playback = {
+                       .stream_name = "Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = CS42L42_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = CS42L42_FORMATS,
+               },
+               .ops = &cs42l42_ops,
+};
+
+static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+       unsigned int hs_det_status;
+       unsigned int int_status;
+
+       /* Mask the auto detect interrupt */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_CODEC_INT_MASK,
+               CS42L42_PDN_DONE_MASK |
+               CS42L42_HSDET_AUTO_DONE_MASK,
+               (1 << CS42L42_PDN_DONE_SHIFT) |
+               (1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+       /* Set hs detect to automatic, disabled mode */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_HSDET_CTL2,
+               CS42L42_HSDET_CTRL_MASK |
+               CS42L42_HSDET_SET_MASK |
+               CS42L42_HSBIAS_REF_MASK |
+               CS42L42_HSDET_AUTO_TIME_MASK,
+               (2 << CS42L42_HSDET_CTRL_SHIFT) |
+               (2 << CS42L42_HSDET_SET_SHIFT) |
+               (0 << CS42L42_HSBIAS_REF_SHIFT) |
+               (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+       /* Read and save the hs detection result */
+       regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status);
+
+       cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >>
+                               CS42L42_HSDET_TYPE_SHIFT;
+
+       /* Set up button detection */
+       if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) ||
+             (cs42l42->hs_type == CS42L42_PLUG_OMTP)) {
+               /* Set auto HS bias settings to default */
+               regmap_update_bits(cs42l42->regmap,
+                       CS42L42_HSBIAS_SC_AUTOCTL,
+                       CS42L42_HSBIAS_SENSE_EN_MASK |
+                       CS42L42_AUTO_HSBIAS_HIZ_MASK |
+                       CS42L42_TIP_SENSE_EN_MASK |
+                       CS42L42_HSBIAS_SENSE_TRIP_MASK,
+                       (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+                       (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+                       (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+                       (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+               /* Set up hs detect level sensitivity */
+               regmap_update_bits(cs42l42->regmap,
+                       CS42L42_MIC_DET_CTL1,
+                       CS42L42_LATCH_TO_VP_MASK |
+                       CS42L42_EVENT_STAT_SEL_MASK |
+                       CS42L42_HS_DET_LEVEL_MASK,
+                       (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+                       (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+                       (cs42l42->bias_thresholds[0] <<
+                       CS42L42_HS_DET_LEVEL_SHIFT));
+
+               /* Set auto HS bias settings to default */
+               regmap_update_bits(cs42l42->regmap,
+                       CS42L42_HSBIAS_SC_AUTOCTL,
+                       CS42L42_HSBIAS_SENSE_EN_MASK |
+                       CS42L42_AUTO_HSBIAS_HIZ_MASK |
+                       CS42L42_TIP_SENSE_EN_MASK |
+                       CS42L42_HSBIAS_SENSE_TRIP_MASK,
+                       (1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+                       (1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+                       (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+                       (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+               /* Turn on level detect circuitry */
+               regmap_update_bits(cs42l42->regmap,
+                       CS42L42_MISC_DET_CTL,
+                       CS42L42_DETECT_MODE_MASK |
+                       CS42L42_HSBIAS_CTL_MASK |
+                       CS42L42_PDN_MIC_LVL_DET_MASK,
+                       (0 << CS42L42_DETECT_MODE_SHIFT) |
+                       (3 << CS42L42_HSBIAS_CTL_SHIFT) |
+                       (0 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+               msleep(cs42l42->btn_det_init_dbnce);
+
+               /* Clear any button interrupts before unmasking them */
+               regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2,
+                           &int_status);
+
+               /* Unmask button detect interrupts */
+               regmap_update_bits(cs42l42->regmap,
+                       CS42L42_DET_INT2_MASK,
+                       CS42L42_M_DETECT_TF_MASK |
+                       CS42L42_M_DETECT_FT_MASK |
+                       CS42L42_M_HSBIAS_HIZ_MASK |
+                       CS42L42_M_SHORT_RLS_MASK |
+                       CS42L42_M_SHORT_DET_MASK,
+                       (0 << CS42L42_M_DETECT_TF_SHIFT) |
+                       (0 << CS42L42_M_DETECT_FT_SHIFT) |
+                       (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+                       (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+                       (1 << CS42L42_M_SHORT_DET_SHIFT));
+       } else {
+               /* Make sure button detect and HS bias circuits are off */
+               regmap_update_bits(cs42l42->regmap,
+                       CS42L42_MISC_DET_CTL,
+                       CS42L42_DETECT_MODE_MASK |
+                       CS42L42_HSBIAS_CTL_MASK |
+                       CS42L42_PDN_MIC_LVL_DET_MASK,
+                       (0 << CS42L42_DETECT_MODE_SHIFT) |
+                       (1 << CS42L42_HSBIAS_CTL_SHIFT) |
+                       (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+       }
+
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_DAC_CTL2,
+                               CS42L42_HPOUT_PULLDOWN_MASK |
+                               CS42L42_HPOUT_LOAD_MASK |
+                               CS42L42_HPOUT_CLAMP_MASK |
+                               CS42L42_DAC_HPF_EN_MASK |
+                               CS42L42_DAC_MON_EN_MASK,
+                               (0 << CS42L42_HPOUT_PULLDOWN_SHIFT) |
+                               (0 << CS42L42_HPOUT_LOAD_SHIFT) |
+                               (0 << CS42L42_HPOUT_CLAMP_SHIFT) |
+                               (1 << CS42L42_DAC_HPF_EN_SHIFT) |
+                               (0 << CS42L42_DAC_MON_EN_SHIFT));
+
+       /* Unmask tip sense interrupts */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_TSRS_PLUG_INT_MASK,
+               CS42L42_RS_PLUG_MASK |
+               CS42L42_RS_UNPLUG_MASK |
+               CS42L42_TS_PLUG_MASK |
+               CS42L42_TS_UNPLUG_MASK,
+               (1 << CS42L42_RS_PLUG_SHIFT) |
+               (1 << CS42L42_RS_UNPLUG_SHIFT) |
+               (0 << CS42L42_TS_PLUG_SHIFT) |
+               (0 << CS42L42_TS_UNPLUG_SHIFT));
+}
+
+static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+       /* Mask tip sense interrupts */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_TSRS_PLUG_INT_MASK,
+                               CS42L42_RS_PLUG_MASK |
+                               CS42L42_RS_UNPLUG_MASK |
+                               CS42L42_TS_PLUG_MASK |
+                               CS42L42_TS_UNPLUG_MASK,
+                               (1 << CS42L42_RS_PLUG_SHIFT) |
+                               (1 << CS42L42_RS_UNPLUG_SHIFT) |
+                               (1 << CS42L42_TS_PLUG_SHIFT) |
+                               (1 << CS42L42_TS_UNPLUG_SHIFT));
+
+       /* Make sure button detect and HS bias circuits are off */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_MISC_DET_CTL,
+                               CS42L42_DETECT_MODE_MASK |
+                               CS42L42_HSBIAS_CTL_MASK |
+                               CS42L42_PDN_MIC_LVL_DET_MASK,
+                               (0 << CS42L42_DETECT_MODE_SHIFT) |
+                               (1 << CS42L42_HSBIAS_CTL_SHIFT) |
+                               (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+       /* Set auto HS bias settings to default */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_HSBIAS_SC_AUTOCTL,
+                               CS42L42_HSBIAS_SENSE_EN_MASK |
+                               CS42L42_AUTO_HSBIAS_HIZ_MASK |
+                               CS42L42_TIP_SENSE_EN_MASK |
+                               CS42L42_HSBIAS_SENSE_TRIP_MASK,
+                               (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+                               (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+                               (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+                               (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+       /* Set hs detect to manual, disabled mode */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_HSDET_CTL2,
+                               CS42L42_HSDET_CTRL_MASK |
+                               CS42L42_HSDET_SET_MASK |
+                               CS42L42_HSBIAS_REF_MASK |
+                               CS42L42_HSDET_AUTO_TIME_MASK,
+                               (0 << CS42L42_HSDET_CTRL_SHIFT) |
+                               (2 << CS42L42_HSDET_SET_SHIFT) |
+                               (0 << CS42L42_HSBIAS_REF_SHIFT) |
+                               (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_DAC_CTL2,
+                               CS42L42_HPOUT_PULLDOWN_MASK |
+                               CS42L42_HPOUT_LOAD_MASK |
+                               CS42L42_HPOUT_CLAMP_MASK |
+                               CS42L42_DAC_HPF_EN_MASK |
+                               CS42L42_DAC_MON_EN_MASK,
+                               (8 << CS42L42_HPOUT_PULLDOWN_SHIFT) |
+                               (0 << CS42L42_HPOUT_LOAD_SHIFT) |
+                               (1 << CS42L42_HPOUT_CLAMP_SHIFT) |
+                               (1 << CS42L42_DAC_HPF_EN_SHIFT) |
+                               (1 << CS42L42_DAC_MON_EN_SHIFT));
+
+       /* Power up HS bias to 2.7V */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_MISC_DET_CTL,
+                               CS42L42_DETECT_MODE_MASK |
+                               CS42L42_HSBIAS_CTL_MASK |
+                               CS42L42_PDN_MIC_LVL_DET_MASK,
+                               (0 << CS42L42_DETECT_MODE_SHIFT) |
+                               (3 << CS42L42_HSBIAS_CTL_SHIFT) |
+                               (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+       /* Wait for HS bias to ramp up */
+       msleep(cs42l42->hs_bias_ramp_time);
+
+       /* Unmask auto detect interrupt */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_CODEC_INT_MASK,
+                               CS42L42_PDN_DONE_MASK |
+                               CS42L42_HSDET_AUTO_DONE_MASK,
+                               (1 << CS42L42_PDN_DONE_SHIFT) |
+                               (0 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+       /* Set hs detect to automatic, enabled mode */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_HSDET_CTL2,
+                               CS42L42_HSDET_CTRL_MASK |
+                               CS42L42_HSDET_SET_MASK |
+                               CS42L42_HSBIAS_REF_MASK |
+                               CS42L42_HSDET_AUTO_TIME_MASK,
+                               (3 << CS42L42_HSDET_CTRL_SHIFT) |
+                               (2 << CS42L42_HSDET_SET_SHIFT) |
+                               (0 << CS42L42_HSBIAS_REF_SHIFT) |
+                               (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+}
+
+static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+       /* Mask button detect interrupts */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_DET_INT2_MASK,
+               CS42L42_M_DETECT_TF_MASK |
+               CS42L42_M_DETECT_FT_MASK |
+               CS42L42_M_HSBIAS_HIZ_MASK |
+               CS42L42_M_SHORT_RLS_MASK |
+               CS42L42_M_SHORT_DET_MASK,
+               (1 << CS42L42_M_DETECT_TF_SHIFT) |
+               (1 << CS42L42_M_DETECT_FT_SHIFT) |
+               (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+               (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+               (1 << CS42L42_M_SHORT_DET_SHIFT));
+
+       /* Ground HS bias */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_MISC_DET_CTL,
+                               CS42L42_DETECT_MODE_MASK |
+                               CS42L42_HSBIAS_CTL_MASK |
+                               CS42L42_PDN_MIC_LVL_DET_MASK,
+                               (0 << CS42L42_DETECT_MODE_SHIFT) |
+                               (1 << CS42L42_HSBIAS_CTL_SHIFT) |
+                               (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT));
+
+       /* Set auto HS bias settings to default */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_HSBIAS_SC_AUTOCTL,
+                               CS42L42_HSBIAS_SENSE_EN_MASK |
+                               CS42L42_AUTO_HSBIAS_HIZ_MASK |
+                               CS42L42_TIP_SENSE_EN_MASK |
+                               CS42L42_HSBIAS_SENSE_TRIP_MASK,
+                               (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) |
+                               (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) |
+                               (0 << CS42L42_TIP_SENSE_EN_SHIFT) |
+                               (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT));
+
+       /* Set hs detect to manual, disabled mode */
+       regmap_update_bits(cs42l42->regmap,
+                               CS42L42_HSDET_CTL2,
+                               CS42L42_HSDET_CTRL_MASK |
+                               CS42L42_HSDET_SET_MASK |
+                               CS42L42_HSBIAS_REF_MASK |
+                               CS42L42_HSDET_AUTO_TIME_MASK,
+                               (0 << CS42L42_HSDET_CTRL_SHIFT) |
+                               (2 << CS42L42_HSDET_SET_SHIFT) |
+                               (0 << CS42L42_HSBIAS_REF_SHIFT) |
+                               (3 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+}
+
+static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42)
+{
+       int bias_level;
+       unsigned int detect_status;
+
+       /* Mask button detect interrupts */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_DET_INT2_MASK,
+               CS42L42_M_DETECT_TF_MASK |
+               CS42L42_M_DETECT_FT_MASK |
+               CS42L42_M_HSBIAS_HIZ_MASK |
+               CS42L42_M_SHORT_RLS_MASK |
+               CS42L42_M_SHORT_DET_MASK,
+               (1 << CS42L42_M_DETECT_TF_SHIFT) |
+               (1 << CS42L42_M_DETECT_FT_SHIFT) |
+               (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+               (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+               (1 << CS42L42_M_SHORT_DET_SHIFT));
+
+       usleep_range(cs42l42->btn_det_event_dbnce * 1000,
+                    cs42l42->btn_det_event_dbnce * 2000);
+
+       /* Test all 4 level detect biases */
+       bias_level = 1;
+       do {
+               /* Adjust button detect level sensitivity */
+               regmap_update_bits(cs42l42->regmap,
+                       CS42L42_MIC_DET_CTL1,
+                       CS42L42_LATCH_TO_VP_MASK |
+                       CS42L42_EVENT_STAT_SEL_MASK |
+                       CS42L42_HS_DET_LEVEL_MASK,
+                       (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+                       (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+                       (cs42l42->bias_thresholds[bias_level] <<
+                       CS42L42_HS_DET_LEVEL_SHIFT));
+
+               regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2,
+                               &detect_status);
+       } while ((detect_status & CS42L42_HS_TRUE_MASK) &&
+               (++bias_level < CS42L42_NUM_BIASES));
+
+       switch (bias_level) {
+       case 1: /* Function C button press */
+               dev_dbg(cs42l42->codec->dev, "Function C button press\n");
+               break;
+       case 2: /* Function B button press */
+               dev_dbg(cs42l42->codec->dev, "Function B button press\n");
+               break;
+       case 3: /* Function D button press */
+               dev_dbg(cs42l42->codec->dev, "Function D button press\n");
+               break;
+       case 4: /* Function A button press */
+               dev_dbg(cs42l42->codec->dev, "Function A button press\n");
+               break;
+       }
+
+       /* Set button detect level sensitivity back to default */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_MIC_DET_CTL1,
+               CS42L42_LATCH_TO_VP_MASK |
+               CS42L42_EVENT_STAT_SEL_MASK |
+               CS42L42_HS_DET_LEVEL_MASK,
+               (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+               (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+               (cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT));
+
+       /* Clear any button interrupts before unmasking them */
+       regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2,
+                   &detect_status);
+
+       /* Unmask button detect interrupts */
+       regmap_update_bits(cs42l42->regmap,
+               CS42L42_DET_INT2_MASK,
+               CS42L42_M_DETECT_TF_MASK |
+               CS42L42_M_DETECT_FT_MASK |
+               CS42L42_M_HSBIAS_HIZ_MASK |
+               CS42L42_M_SHORT_RLS_MASK |
+               CS42L42_M_SHORT_DET_MASK,
+               (0 << CS42L42_M_DETECT_TF_SHIFT) |
+               (0 << CS42L42_M_DETECT_FT_SHIFT) |
+               (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+               (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+               (1 << CS42L42_M_SHORT_DET_SHIFT));
+}
+
+struct cs42l42_irq_params {
+       u16 status_addr;
+       u16 mask_addr;
+       u8 mask;
+};
+
+static const struct cs42l42_irq_params irq_params_table[] = {
+       {CS42L42_ADC_OVFL_STATUS, CS42L42_ADC_OVFL_INT_MASK,
+               CS42L42_ADC_OVFL_VAL_MASK},
+       {CS42L42_MIXER_STATUS, CS42L42_MIXER_INT_MASK,
+               CS42L42_MIXER_VAL_MASK},
+       {CS42L42_SRC_STATUS, CS42L42_SRC_INT_MASK,
+               CS42L42_SRC_VAL_MASK},
+       {CS42L42_ASP_RX_STATUS, CS42L42_ASP_RX_INT_MASK,
+               CS42L42_ASP_RX_VAL_MASK},
+       {CS42L42_ASP_TX_STATUS, CS42L42_ASP_TX_INT_MASK,
+               CS42L42_ASP_TX_VAL_MASK},
+       {CS42L42_CODEC_STATUS, CS42L42_CODEC_INT_MASK,
+               CS42L42_CODEC_VAL_MASK},
+       {CS42L42_DET_INT_STATUS1, CS42L42_DET_INT1_MASK,
+               CS42L42_DET_INT_VAL1_MASK},
+       {CS42L42_DET_INT_STATUS2, CS42L42_DET_INT2_MASK,
+               CS42L42_DET_INT_VAL2_MASK},
+       {CS42L42_SRCPL_INT_STATUS, CS42L42_SRCPL_INT_MASK,
+               CS42L42_SRCPL_VAL_MASK},
+       {CS42L42_VPMON_STATUS, CS42L42_VPMON_INT_MASK,
+               CS42L42_VPMON_VAL_MASK},
+       {CS42L42_PLL_LOCK_STATUS, CS42L42_PLL_LOCK_INT_MASK,
+               CS42L42_PLL_LOCK_VAL_MASK},
+       {CS42L42_TSRS_PLUG_STATUS, CS42L42_TSRS_PLUG_INT_MASK,
+               CS42L42_TSRS_PLUG_VAL_MASK}
+};
+
+static irqreturn_t cs42l42_irq_thread(int irq, void *data)
+{
+       struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data;
+       struct snd_soc_codec *codec = cs42l42->codec;
+       unsigned int stickies[12];
+       unsigned int masks[12];
+       unsigned int current_plug_status;
+       unsigned int current_button_status;
+       unsigned int i;
+
+       /* Read sticky registers to clear interurpt */
+       for (i = 0; i < ARRAY_SIZE(stickies); i++) {
+               regmap_read(cs42l42->regmap, irq_params_table[i].status_addr,
+                               &(stickies[i]));
+               regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr,
+                               &(masks[i]));
+               stickies[i] = stickies[i] & (~masks[i]) &
+                               irq_params_table[i].mask;
+       }
+
+       /* Read tip sense status before handling type detect */
+       current_plug_status = (stickies[11] &
+               (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >>
+               CS42L42_TS_PLUG_SHIFT;
+
+       /* Read button sense status */
+       current_button_status = stickies[7] &
+               (CS42L42_M_DETECT_TF_MASK |
+               CS42L42_M_DETECT_FT_MASK |
+               CS42L42_M_HSBIAS_HIZ_MASK);
+
+       /* Check auto-detect status */
+       if ((~masks[5]) & irq_params_table[5].mask) {
+               if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) {
+                       cs42l42_process_hs_type_detect(cs42l42);
+                       dev_dbg(codec->dev,
+                               "Auto detect done (%d)\n",
+                               cs42l42->hs_type);
+               }
+       }
+
+       /* Check tip sense status */
+       if ((~masks[11]) & irq_params_table[11].mask) {
+               switch (current_plug_status) {
+               case CS42L42_TS_PLUG:
+                       if (cs42l42->plug_state != CS42L42_TS_PLUG) {
+                               cs42l42->plug_state = CS42L42_TS_PLUG;
+                               cs42l42_init_hs_type_detect(cs42l42);
+                       }
+                       break;
+
+               case CS42L42_TS_UNPLUG:
+                       if (cs42l42->plug_state != CS42L42_TS_UNPLUG) {
+                               cs42l42->plug_state = CS42L42_TS_UNPLUG;
+                               cs42l42_cancel_hs_type_detect(cs42l42);
+                               dev_dbg(codec->dev,
+                                       "Unplug event\n");
+                       }
+                       break;
+
+               default:
+                       if (cs42l42->plug_state != CS42L42_TS_TRANS)
+                               cs42l42->plug_state = CS42L42_TS_TRANS;
+               }
+       }
+
+       /* Check button detect status */
+       if ((~masks[7]) & irq_params_table[7].mask) {
+               if (!(current_button_status &
+                       CS42L42_M_HSBIAS_HIZ_MASK)) {
+
+                       if (current_button_status &
+                               CS42L42_M_DETECT_TF_MASK) {
+                               dev_dbg(codec->dev,
+                                       "Button released\n");
+                       } else if (current_button_status &
+                               CS42L42_M_DETECT_FT_MASK) {
+                               cs42l42_handle_button_press(cs42l42);
+                       }
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42)
+{
+       regmap_update_bits(cs42l42->regmap, CS42L42_ADC_OVFL_INT_MASK,
+                       CS42L42_ADC_OVFL_MASK,
+                       (1 << CS42L42_ADC_OVFL_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_MIXER_INT_MASK,
+                       CS42L42_MIX_CHB_OVFL_MASK |
+                       CS42L42_MIX_CHA_OVFL_MASK |
+                       CS42L42_EQ_OVFL_MASK |
+                       CS42L42_EQ_BIQUAD_OVFL_MASK,
+                       (1 << CS42L42_MIX_CHB_OVFL_SHIFT) |
+                       (1 << CS42L42_MIX_CHA_OVFL_SHIFT) |
+                       (1 << CS42L42_EQ_OVFL_SHIFT) |
+                       (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_SRC_INT_MASK,
+                       CS42L42_SRC_ILK_MASK |
+                       CS42L42_SRC_OLK_MASK |
+                       CS42L42_SRC_IUNLK_MASK |
+                       CS42L42_SRC_OUNLK_MASK,
+                       (1 << CS42L42_SRC_ILK_SHIFT) |
+                       (1 << CS42L42_SRC_OLK_SHIFT) |
+                       (1 << CS42L42_SRC_IUNLK_SHIFT) |
+                       (1 << CS42L42_SRC_OUNLK_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_ASP_RX_INT_MASK,
+                       CS42L42_ASPRX_NOLRCK_MASK |
+                       CS42L42_ASPRX_EARLY_MASK |
+                       CS42L42_ASPRX_LATE_MASK |
+                       CS42L42_ASPRX_ERROR_MASK |
+                       CS42L42_ASPRX_OVLD_MASK,
+                       (1 << CS42L42_ASPRX_NOLRCK_SHIFT) |
+                       (1 << CS42L42_ASPRX_EARLY_SHIFT) |
+                       (1 << CS42L42_ASPRX_LATE_SHIFT) |
+                       (1 << CS42L42_ASPRX_ERROR_SHIFT) |
+                       (1 << CS42L42_ASPRX_OVLD_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_ASP_TX_INT_MASK,
+                       CS42L42_ASPTX_NOLRCK_MASK |
+                       CS42L42_ASPTX_EARLY_MASK |
+                       CS42L42_ASPTX_LATE_MASK |
+                       CS42L42_ASPTX_SMERROR_MASK,
+                       (1 << CS42L42_ASPTX_NOLRCK_SHIFT) |
+                       (1 << CS42L42_ASPTX_EARLY_SHIFT) |
+                       (1 << CS42L42_ASPTX_LATE_SHIFT) |
+                       (1 << CS42L42_ASPTX_SMERROR_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK,
+                       CS42L42_PDN_DONE_MASK |
+                       CS42L42_HSDET_AUTO_DONE_MASK,
+                       (1 << CS42L42_PDN_DONE_SHIFT) |
+                       (1 << CS42L42_HSDET_AUTO_DONE_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_SRCPL_INT_MASK,
+                       CS42L42_SRCPL_ADC_LK_MASK |
+                       CS42L42_SRCPL_DAC_LK_MASK |
+                       CS42L42_SRCPL_ADC_UNLK_MASK |
+                       CS42L42_SRCPL_DAC_UNLK_MASK,
+                       (1 << CS42L42_SRCPL_ADC_LK_SHIFT) |
+                       (1 << CS42L42_SRCPL_DAC_LK_SHIFT) |
+                       (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) |
+                       (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT1_MASK,
+                       CS42L42_TIP_SENSE_UNPLUG_MASK |
+                       CS42L42_TIP_SENSE_PLUG_MASK |
+                       CS42L42_HSBIAS_SENSE_MASK,
+                       (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) |
+                       (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) |
+                       (1 << CS42L42_HSBIAS_SENSE_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK,
+                       CS42L42_M_DETECT_TF_MASK |
+                       CS42L42_M_DETECT_FT_MASK |
+                       CS42L42_M_HSBIAS_HIZ_MASK |
+                       CS42L42_M_SHORT_RLS_MASK |
+                       CS42L42_M_SHORT_DET_MASK,
+                       (1 << CS42L42_M_DETECT_TF_SHIFT) |
+                       (1 << CS42L42_M_DETECT_FT_SHIFT) |
+                       (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) |
+                       (1 << CS42L42_M_SHORT_RLS_SHIFT) |
+                       (1 << CS42L42_M_SHORT_DET_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_VPMON_INT_MASK,
+                       CS42L42_VPMON_MASK,
+                       (1 << CS42L42_VPMON_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_PLL_LOCK_INT_MASK,
+                       CS42L42_PLL_LOCK_MASK,
+                       (1 << CS42L42_PLL_LOCK_SHIFT));
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK,
+                       CS42L42_RS_PLUG_MASK |
+                       CS42L42_RS_UNPLUG_MASK |
+                       CS42L42_TS_PLUG_MASK |
+                       CS42L42_TS_UNPLUG_MASK,
+                       (1 << CS42L42_RS_PLUG_SHIFT) |
+                       (1 << CS42L42_RS_UNPLUG_SHIFT) |
+                       (0 << CS42L42_TS_PLUG_SHIFT) |
+                       (0 << CS42L42_TS_UNPLUG_SHIFT));
+}
+
+static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42)
+{
+       unsigned int reg;
+
+       cs42l42->hs_type = CS42L42_PLUG_INVALID;
+
+       /* Latch analog controls to VP power domain */
+       regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1,
+                       CS42L42_LATCH_TO_VP_MASK |
+                       CS42L42_EVENT_STAT_SEL_MASK |
+                       CS42L42_HS_DET_LEVEL_MASK,
+                       (1 << CS42L42_LATCH_TO_VP_SHIFT) |
+                       (0 << CS42L42_EVENT_STAT_SEL_SHIFT) |
+                       (cs42l42->bias_thresholds[0] <<
+                       CS42L42_HS_DET_LEVEL_SHIFT));
+
+       /* Remove ground noise-suppression clamps */
+       regmap_update_bits(cs42l42->regmap,
+                       CS42L42_HS_CLAMP_DISABLE,
+                       CS42L42_HS_CLAMP_DISABLE_MASK,
+                       (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT));
+
+       /* Enable the tip sense circuit */
+       regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL,
+                       CS42L42_TIP_SENSE_CTRL_MASK |
+                       CS42L42_TIP_SENSE_INV_MASK |
+                       CS42L42_TIP_SENSE_DEBOUNCE_MASK,
+                       (3 << CS42L42_TIP_SENSE_CTRL_SHIFT) |
+                       (0 << CS42L42_TIP_SENSE_INV_SHIFT) |
+                       (2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT));
+
+       /* Save the initial status of the tip sense */
+       regmap_read(cs42l42->regmap,
+                         CS42L42_TSRS_PLUG_STATUS,
+                         &reg);
+       cs42l42->plug_state = (((char) reg) &
+                     (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >>
+                     CS42L42_TS_PLUG_SHIFT;
+}
+
+static const unsigned int threshold_defaults[] = {
+       CS42L42_HS_DET_LEVEL_15,
+       CS42L42_HS_DET_LEVEL_8,
+       CS42L42_HS_DET_LEVEL_4,
+       CS42L42_HS_DET_LEVEL_1
+};
+
+static int cs42l42_handle_device_data(struct i2c_client *i2c_client,
+                                       struct cs42l42_private *cs42l42)
+{
+       struct device_node *np = i2c_client->dev.of_node;
+       unsigned int val;
+       unsigned int thresholds[CS42L42_NUM_BIASES];
+       int ret;
+       int i;
+
+       ret = of_property_read_u32(np, "cirrus,ts-inv", &val);
+
+       if (!ret) {
+               switch (val) {
+               case CS42L42_TS_INV_EN:
+               case CS42L42_TS_INV_DIS:
+                       cs42l42->ts_inv = val;
+                       break;
+               default:
+                       dev_err(&i2c_client->dev,
+                               "Wrong cirrus,ts-inv DT value %d\n",
+                               val);
+                       cs42l42->ts_inv = CS42L42_TS_INV_DIS;
+               }
+       } else {
+               cs42l42->ts_inv = CS42L42_TS_INV_DIS;
+       }
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+                       CS42L42_TS_INV_MASK,
+                       (cs42l42->ts_inv << CS42L42_TS_INV_SHIFT));
+
+       ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val);
+
+       if (!ret) {
+               switch (val) {
+               case CS42L42_TS_DBNCE_0:
+               case CS42L42_TS_DBNCE_125:
+               case CS42L42_TS_DBNCE_250:
+               case CS42L42_TS_DBNCE_500:
+               case CS42L42_TS_DBNCE_750:
+               case CS42L42_TS_DBNCE_1000:
+               case CS42L42_TS_DBNCE_1250:
+               case CS42L42_TS_DBNCE_1500:
+                       cs42l42->ts_dbnc_rise = val;
+                       break;
+               default:
+                       dev_err(&i2c_client->dev,
+                               "Wrong cirrus,ts-dbnc-rise DT value %d\n",
+                               val);
+                       cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000;
+               }
+       } else {
+               cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000;
+       }
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+                       CS42L42_TS_RISE_DBNCE_TIME_MASK,
+                       (cs42l42->ts_dbnc_rise <<
+                       CS42L42_TS_RISE_DBNCE_TIME_SHIFT));
+
+       ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val);
+
+       if (!ret) {
+               switch (val) {
+               case CS42L42_TS_DBNCE_0:
+               case CS42L42_TS_DBNCE_125:
+               case CS42L42_TS_DBNCE_250:
+               case CS42L42_TS_DBNCE_500:
+               case CS42L42_TS_DBNCE_750:
+               case CS42L42_TS_DBNCE_1000:
+               case CS42L42_TS_DBNCE_1250:
+               case CS42L42_TS_DBNCE_1500:
+                       cs42l42->ts_dbnc_fall = val;
+                       break;
+               default:
+                       dev_err(&i2c_client->dev,
+                               "Wrong cirrus,ts-dbnc-fall DT value %d\n",
+                               val);
+                       cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0;
+               }
+       } else {
+               cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0;
+       }
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL,
+                       CS42L42_TS_FALL_DBNCE_TIME_MASK,
+                       (cs42l42->ts_dbnc_fall <<
+                       CS42L42_TS_FALL_DBNCE_TIME_SHIFT));
+
+       ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val);
+
+       if (!ret) {
+               if ((val >= CS42L42_BTN_DET_INIT_DBNCE_MIN) &&
+                       (val <= CS42L42_BTN_DET_INIT_DBNCE_MAX))
+                       cs42l42->btn_det_init_dbnce = val;
+               else {
+                       dev_err(&i2c_client->dev,
+                               "Wrong cirrus,btn-det-init-dbnce DT value %d\n",
+                               val);
+                       cs42l42->btn_det_init_dbnce =
+                               CS42L42_BTN_DET_INIT_DBNCE_DEFAULT;
+               }
+       } else {
+               cs42l42->btn_det_init_dbnce =
+                       CS42L42_BTN_DET_INIT_DBNCE_DEFAULT;
+       }
+
+       ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val);
+
+       if (!ret) {
+               if ((val >= CS42L42_BTN_DET_EVENT_DBNCE_MIN) &&
+                       (val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX))
+                       cs42l42->btn_det_event_dbnce = val;
+               else {
+                       dev_err(&i2c_client->dev,
+                       "Wrong cirrus,btn-det-event-dbnce DT value %d\n", val);
+                       cs42l42->btn_det_event_dbnce =
+                               CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT;
+               }
+       } else {
+               cs42l42->btn_det_event_dbnce =
+                       CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT;
+       }
+
+       ret = of_property_read_u32_array(np, "cirrus,bias-lvls",
+                                  (u32 *)thresholds, CS42L42_NUM_BIASES);
+
+       if (!ret) {
+               for (i = 0; i < CS42L42_NUM_BIASES; i++) {
+                       if ((thresholds[i] >= CS42L42_HS_DET_LEVEL_MIN) &&
+                               (thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX))
+                               cs42l42->bias_thresholds[i] = thresholds[i];
+                       else {
+                               dev_err(&i2c_client->dev,
+                               "Wrong cirrus,bias-lvls[%d] DT value %d\n", i,
+                                       thresholds[i]);
+                               cs42l42->bias_thresholds[i] =
+                                       threshold_defaults[i];
+                       }
+               }
+       } else {
+               for (i = 0; i < CS42L42_NUM_BIASES; i++)
+                       cs42l42->bias_thresholds[i] = threshold_defaults[i];
+       }
+
+       ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val);
+
+       if (!ret) {
+               switch (val) {
+               case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL:
+                       cs42l42->hs_bias_ramp_rate = val;
+                       cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME0;
+                       break;
+               case CS42L42_HSBIAS_RAMP_FAST:
+                       cs42l42->hs_bias_ramp_rate = val;
+                       cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME1;
+                       break;
+               case CS42L42_HSBIAS_RAMP_SLOW:
+                       cs42l42->hs_bias_ramp_rate = val;
+                       cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+                       break;
+               case CS42L42_HSBIAS_RAMP_SLOWEST:
+                       cs42l42->hs_bias_ramp_rate = val;
+                       cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3;
+                       break;
+               default:
+                       dev_err(&i2c_client->dev,
+                               "Wrong cirrus,hs-bias-ramp-rate DT value %d\n",
+                               val);
+                       cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW;
+                       cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+               }
+       } else {
+               cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW;
+               cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2;
+       }
+
+       regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL,
+                       CS42L42_HSBIAS_RAMP_MASK,
+                       (cs42l42->hs_bias_ramp_rate <<
+                       CS42L42_HSBIAS_RAMP_SHIFT));
+
+       return 0;
+}
+
+static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
+                                      const struct i2c_device_id *id)
+{
+       struct cs42l42_private *cs42l42;
+       int ret, i;
+       unsigned int devid = 0;
+       unsigned int reg;
+
+       cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private),
+                              GFP_KERNEL);
+       if (!cs42l42)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c_client, cs42l42);
+
+       cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap);
+       if (IS_ERR(cs42l42->regmap)) {
+               ret = PTR_ERR(cs42l42->regmap);
+               dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++)
+               cs42l42->supplies[i].supply = cs42l42_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c_client->dev,
+                                     ARRAY_SIZE(cs42l42->supplies),
+                                     cs42l42->supplies);
+       if (ret != 0) {
+               dev_err(&i2c_client->dev,
+                       "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies),
+                                   cs42l42->supplies);
+       if (ret != 0) {
+               dev_err(&i2c_client->dev,
+                       "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       /* Reset the Device */
+       cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+               "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(cs42l42->reset_gpio))
+               return PTR_ERR(cs42l42->reset_gpio);
+
+       if (cs42l42->reset_gpio) {
+               dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
+               gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+       }
+       mdelay(3);
+
+       /* Request IRQ */
+       ret = devm_request_threaded_irq(&i2c_client->dev,
+                       i2c_client->irq,
+                       NULL, cs42l42_irq_thread,
+                       IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+                       "cs42l42", cs42l42);
+
+       if (ret != 0)
+               dev_err(&i2c_client->dev,
+                       "Failed to request IRQ: %d\n", ret);
+
+       /* initialize codec */
+       ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, &reg);
+       devid = (reg & 0xFF) << 12;
+
+       ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, &reg);
+       devid |= (reg & 0xFF) << 4;
+
+       ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, &reg);
+       devid |= (reg & 0xF0) >> 4;
+
+       if (devid != CS42L42_CHIP_ID) {
+               ret = -ENODEV;
+               dev_err(&i2c_client->dev,
+                       "CS42L42 Device ID (%X). Expected %X\n",
+                       devid, CS42L42_CHIP_ID);
+               return ret;
+       }
+
+       ret = regmap_read(cs42l42->regmap, CS42L42_REVID, &reg);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+               return ret;
+       }
+
+       dev_info(&i2c_client->dev,
+                "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF);
+
+       /* Power up the codec */
+       regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1,
+                       CS42L42_ASP_DAO_PDN_MASK |
+                       CS42L42_ASP_DAI_PDN_MASK |
+                       CS42L42_MIXER_PDN_MASK |
+                       CS42L42_EQ_PDN_MASK |
+                       CS42L42_HP_PDN_MASK |
+                       CS42L42_ADC_PDN_MASK |
+                       CS42L42_PDN_ALL_MASK,
+                       (1 << CS42L42_ASP_DAO_PDN_SHIFT) |
+                       (1 << CS42L42_ASP_DAI_PDN_SHIFT) |
+                       (1 << CS42L42_MIXER_PDN_SHIFT) |
+                       (1 << CS42L42_EQ_PDN_SHIFT) |
+                       (1 << CS42L42_HP_PDN_SHIFT) |
+                       (1 << CS42L42_ADC_PDN_SHIFT) |
+                       (0 << CS42L42_PDN_ALL_SHIFT));
+
+       if (i2c_client->dev.of_node) {
+               ret = cs42l42_handle_device_data(i2c_client, cs42l42);
+               if (ret != 0)
+                       return ret;
+       }
+
+       /* Setup headset detection */
+       cs42l42_setup_hs_type_detect(cs42l42);
+
+       /* Mask/Unmask Interrupts */
+       cs42l42_set_interrupt_masks(cs42l42);
+
+       /* Register codec for machine driver */
+       ret =  snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_dev_cs42l42, &cs42l42_dai, 1);
+       if (ret < 0)
+               goto err_disable;
+       return 0;
+
+err_disable:
+       regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+                               cs42l42->supplies);
+       return ret;
+}
+
+static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
+{
+       struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);
+
+       snd_soc_unregister_codec(&i2c_client->dev);
+
+       /* Hold down reset */
+       if (cs42l42->reset_gpio)
+               gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int cs42l42_runtime_suspend(struct device *dev)
+{
+       struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
+
+       regcache_cache_only(cs42l42->regmap, true);
+       regcache_mark_dirty(cs42l42->regmap);
+
+       /* Hold down reset */
+       if (cs42l42->reset_gpio)
+               gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
+
+       /* remove power */
+       regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
+                               cs42l42->supplies);
+
+       return 0;
+}
+
+static int cs42l42_runtime_resume(struct device *dev)
+{
+       struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
+       int ret;
+
+       /* Enable power */
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies),
+                                       cs42l42->supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable supplies: %d\n",
+                       ret);
+               return ret;
+       }
+
+       if (cs42l42->reset_gpio)
+               gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+
+       regcache_cache_only(cs42l42->regmap, false);
+       regcache_sync(cs42l42->regmap);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs42l42_runtime_pm = {
+       SET_RUNTIME_PM_OPS(cs42l42_runtime_suspend, cs42l42_runtime_resume,
+                          NULL)
+};
+
+static const struct of_device_id cs42l42_of_match[] = {
+       { .compatible = "cirrus,cs42l42", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cs42l42_of_match);
+
+
+static const struct i2c_device_id cs42l42_id[] = {
+       {"cs42l42", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs42l42_id);
+
+static struct i2c_driver cs42l42_i2c_driver = {
+       .driver = {
+               .name = "cs42l42",
+               .pm = &cs42l42_runtime_pm,
+               .of_match_table = cs42l42_of_match,
+               },
+       .id_table = cs42l42_id,
+       .probe = cs42l42_i2c_probe,
+       .remove = cs42l42_i2c_remove,
+};
+
+module_i2c_driver(cs42l42_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L42 driver");
+MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
new file mode 100644 (file)
index 0000000..d87a0a5
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ * cs42l42.h -- CS42L42 ALSA SoC audio driver header
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: James Schulman <james.schulman@cirrus.com>
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ * Author: Michael White <michael.white@cirrus.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 __CS42L42_H__
+#define __CS42L42_H__
+
+#define CS42L42_PAGE_REGISTER  0x00    /* Page Select Register */
+#define CS42L42_WIN_START      0x00
+#define CS42L42_WIN_LEN                0x100
+#define CS42L42_RANGE_MIN      0x00
+#define CS42L42_RANGE_MAX      0x7F
+
+#define CS42L42_PAGE_10                0x1000
+#define CS42L42_PAGE_11                0x1100
+#define CS42L42_PAGE_12                0x1200
+#define CS42L42_PAGE_13                0x1300
+#define CS42L42_PAGE_15                0x1500
+#define CS42L42_PAGE_19                0x1900
+#define CS42L42_PAGE_1B                0x1B00
+#define CS42L42_PAGE_1C                0x1C00
+#define CS42L42_PAGE_1D                0x1D00
+#define CS42L42_PAGE_1F                0x1F00
+#define CS42L42_PAGE_20                0x2000
+#define CS42L42_PAGE_21                0x2100
+#define CS42L42_PAGE_23                0x2300
+#define CS42L42_PAGE_24                0x2400
+#define CS42L42_PAGE_25                0x2500
+#define CS42L42_PAGE_26                0x2600
+#define CS42L42_PAGE_28                0x2800
+#define CS42L42_PAGE_29                0x2900
+#define CS42L42_PAGE_2A                0x2A00
+#define CS42L42_PAGE_30                0x3000
+
+#define CS42L42_CHIP_ID                0x42A42
+
+/* Page 0x10 Global Registers */
+#define CS42L42_DEVID_AB               (CS42L42_PAGE_10 + 0x01)
+#define CS42L42_DEVID_CD               (CS42L42_PAGE_10 + 0x02)
+#define CS42L42_DEVID_E                        (CS42L42_PAGE_10 + 0x03)
+#define CS42L42_FABID                  (CS42L42_PAGE_10 + 0x04)
+#define CS42L42_REVID                  (CS42L42_PAGE_10 + 0x05)
+#define CS42L42_FRZ_CTL                        (CS42L42_PAGE_10 + 0x06)
+
+#define CS42L42_SRC_CTL                        (CS42L42_PAGE_10 + 0x07)
+#define CS42L42_SRC_BYPASS_DAC_SHIFT   1
+#define CS42L42_SRC_BYPASS_DAC_MASK    (1 << CS42L42_SRC_BYPASS_DAC_SHIFT)
+
+#define CS42L42_MCLK_STATUS            (CS42L42_PAGE_10 + 0x08)
+
+#define CS42L42_MCLK_CTL               (CS42L42_PAGE_10 + 0x09)
+#define CS42L42_INTERNAL_FS_SHIFT      1
+#define CS42L42_INTERNAL_FS_MASK       (1 << CS42L42_INTERNAL_FS_SHIFT)
+
+#define CS42L42_SFTRAMP_RATE           (CS42L42_PAGE_10 + 0x0A)
+#define CS42L42_I2C_DEBOUNCE           (CS42L42_PAGE_10 + 0x0E)
+#define CS42L42_I2C_STRETCH            (CS42L42_PAGE_10 + 0x0F)
+#define CS42L42_I2C_TIMEOUT            (CS42L42_PAGE_10 + 0x10)
+
+/* Page 0x11 Power and Headset Detect Registers */
+#define CS42L42_PWR_CTL1               (CS42L42_PAGE_11 + 0x01)
+#define CS42L42_ASP_DAO_PDN_SHIFT      7
+#define CS42L42_ASP_DAO_PDN_MASK       (1 << CS42L42_ASP_DAO_PDN_SHIFT)
+#define CS42L42_ASP_DAI_PDN_SHIFT      6
+#define CS42L42_ASP_DAI_PDN_MASK       (1 << CS42L42_ASP_DAI_PDN_SHIFT)
+#define CS42L42_MIXER_PDN_SHIFT                5
+#define CS42L42_MIXER_PDN_MASK         (1 << CS42L42_MIXER_PDN_SHIFT)
+#define CS42L42_EQ_PDN_SHIFT           4
+#define CS42L42_EQ_PDN_MASK            (1 << CS42L42_EQ_PDN_SHIFT)
+#define CS42L42_HP_PDN_SHIFT           3
+#define CS42L42_HP_PDN_MASK            (1 << CS42L42_HP_PDN_SHIFT)
+#define CS42L42_ADC_PDN_SHIFT          2
+#define CS42L42_ADC_PDN_MASK           (1 << CS42L42_HP_PDN_SHIFT)
+#define CS42L42_PDN_ALL_SHIFT          0
+#define CS42L42_PDN_ALL_MASK           (1 << CS42L42_PDN_ALL_SHIFT)
+
+#define CS42L42_PWR_CTL2               (CS42L42_PAGE_11 + 0x02)
+#define CS42L42_ADC_SRC_PDNB_SHIFT     0
+#define CS42L42_ADC_SRC_PDNB_MASK      (1 << CS42L42_ADC_SRC_PDNB_SHIFT)
+#define CS42L42_DAC_SRC_PDNB_SHIFT     1
+#define CS42L42_DAC_SRC_PDNB_MASK      (1 << CS42L42_DAC_SRC_PDNB_SHIFT)
+#define CS42L42_ASP_DAI1_PDN_SHIFT     2
+#define CS42L42_ASP_DAI1_PDN_MASK      (1 << CS42L42_ASP_DAI1_PDN_SHIFT)
+#define CS42L42_SRC_PDN_OVERRIDE_SHIFT 3
+#define CS42L42_SRC_PDN_OVERRIDE_MASK  (1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT)
+#define CS42L42_DISCHARGE_FILT_SHIFT   4
+#define CS42L42_DISCHARGE_FILT_MASK    (1 << CS42L42_DISCHARGE_FILT_SHIFT)
+
+#define CS42L42_PWR_CTL3                       (CS42L42_PAGE_11 + 0x03)
+#define CS42L42_RING_SENSE_PDNB_SHIFT          1
+#define CS42L42_RING_SENSE_PDNB_MASK           (1 << \
+                                       CS42L42_RING_SENSE_PDNB_SHIFT)
+#define CS42L42_VPMON_PDNB_SHIFT               2
+#define CS42L42_VPMON_PDNB_MASK                        (1 << \
+                                       CS42L42_VPMON_PDNB_SHIFT)
+#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT      5
+#define CS42L42_SW_CLK_STP_STAT_SEL_MASK       (3 << \
+                                       CS42L42_SW_CLK_STP_STAT_SEL_SHIFT)
+
+#define CS42L42_RSENSE_CTL1                    (CS42L42_PAGE_11 + 0x04)
+#define CS42L42_RS_TRIM_R_SHIFT                        0
+#define CS42L42_RS_TRIM_R_MASK                 (1 << \
+                                       CS42L42_RS_TRIM_R_SHIFT)
+#define CS42L42_RS_TRIM_T_SHIFT                        1
+#define CS42L42_RS_TRIM_T_MASK                 (1 << \
+                                       CS42L42_RS_TRIM_T_SHIFT)
+#define CS42L42_HPREF_RS_SHIFT                 2
+#define CS42L42_HPREF_RS_MASK                  (1 << \
+                                       CS42L42_HPREF_RS_SHIFT)
+#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT       3
+#define CS42L42_HSBIAS_FILT_REF_RS_MASK                (1 << \
+                                       CS42L42_HSBIAS_FILT_REF_RS_SHIFT)
+#define CS42L42_RING_SENSE_PU_HIZ_SHIFT                6
+#define CS42L42_RING_SENSE_PU_HIZ_MASK         (1 << \
+                                       CS42L42_RING_SENSE_PU_HIZ_SHIFT)
+
+#define CS42L42_RSENSE_CTL2            (CS42L42_PAGE_11 + 0x05)
+#define CS42L42_TS_RS_GATE_SHIFT       7
+#define CS42L42_TS_RS_GATE_MAS         (1 << CS42L42_TS_RS_GATE_SHIFT)
+
+#define CS42L42_OSC_SWITCH             (CS42L42_PAGE_11 + 0x07)
+#define CS42L42_SCLK_PRESENT_SHIFT     0
+#define CS42L42_SCLK_PRESENT_MASK      (1 << CS42L42_SCLK_PRESENT_SHIFT)
+
+#define CS42L42_OSC_SWITCH_STATUS      (CS42L42_PAGE_11 + 0x09)
+#define CS42L42_OSC_SW_SEL_STAT_SHIFT  0
+#define CS42L42_OSC_SW_SEL_STAT_MASK   (3 << CS42L42_OSC_SW_SEL_STAT_SHIFT)
+#define CS42L42_OSC_PDNB_STAT_SHIFT    2
+#define CS42L42_OSC_PDNB_STAT_MASK     (1 << CS42L42_OSC_SW_SEL_STAT_SHIFT)
+
+#define CS42L42_RSENSE_CTL3                    (CS42L42_PAGE_11 + 0x12)
+#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT       0
+#define CS42L42_RS_RISE_DBNCE_TIME_MASK                (7 << \
+                                       CS42L42_RS_RISE_DBNCE_TIME_SHIFT)
+#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT       3
+#define CS42L42_RS_FALL_DBNCE_TIME_MASK                (7 << \
+                                       CS42L42_RS_FALL_DBNCE_TIME_SHIFT)
+#define CS42L42_RS_PU_EN_SHIFT                 6
+#define CS42L42_RS_PU_EN_MASK                  (1 << \
+                                       CS42L42_RS_PU_EN_SHIFT)
+#define CS42L42_RS_INV_SHIFT                   7
+#define CS42L42_RS_INV_MASK                    (1 << \
+                                       CS42L42_RS_INV_SHIFT)
+
+#define CS42L42_TSENSE_CTL                     (CS42L42_PAGE_11 + 0x13)
+#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT       0
+#define CS42L42_TS_RISE_DBNCE_TIME_MASK                (7 << \
+                                       CS42L42_TS_RISE_DBNCE_TIME_SHIFT)
+#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT       3
+#define CS42L42_TS_FALL_DBNCE_TIME_MASK                (7 << \
+                                       CS42L42_TS_FALL_DBNCE_TIME_SHIFT)
+#define CS42L42_TS_INV_SHIFT                   7
+#define CS42L42_TS_INV_MASK                    (1 << \
+                                       CS42L42_TS_INV_SHIFT)
+
+#define CS42L42_TSRS_INT_DISABLE       (CS42L42_PAGE_11 + 0x14)
+#define CS42L42_D_RS_PLUG_DBNC_SHIFT   0
+#define CS42L42_D_RS_PLUG_DBNC_MASK    (1 << CS42L42_D_RS_PLUG_DBNC_SHIFT)
+#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT 1
+#define CS42L42_D_RS_UNPLUG_DBNC_MASK  (1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT)
+#define CS42L42_D_TS_PLUG_DBNC_SHIFT   2
+#define CS42L42_D_TS_PLUG_DBNC_MASK    (1 << CS42L42_D_TS_PLUG_DBNC_SHIFT)
+#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT 3
+#define CS42L42_D_TS_UNPLUG_DBNC_MASK  (1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT)
+
+#define CS42L42_TRSENSE_STATUS         (CS42L42_PAGE_11 + 0x15)
+#define CS42L42_RS_PLUG_DBNC_SHIFT     0
+#define CS42L42_RS_PLUG_DBNC_MASK      (1 << CS42L42_RS_PLUG_DBNC_SHIFT)
+#define CS42L42_RS_UNPLUG_DBNC_SHIFT   1
+#define CS42L42_RS_UNPLUG_DBNC_MASK    (1 << CS42L42_RS_UNPLUG_DBNC_SHIFT)
+#define CS42L42_TS_PLUG_DBNC_SHIFT     2
+#define CS42L42_TS_PLUG_DBNC_MASK      (1 << CS42L42_TS_PLUG_DBNC_SHIFT)
+#define CS42L42_TS_UNPLUG_DBNC_SHIFT   3
+#define CS42L42_TS_UNPLUG_DBNC_MASK    (1 << CS42L42_TS_UNPLUG_DBNC_SHIFT)
+
+#define CS42L42_HSDET_CTL1             (CS42L42_PAGE_11 + 0x1F)
+#define CS42L42_HSDET_COMP1_LVL_SHIFT  0
+#define CS42L42_HSDET_COMP1_LVL_MASK   (15 << CS42L42_HSDET_COMP1_LVL_SHIFT)
+#define CS42L42_HSDET_COMP2_LVL_SHIFT  4
+#define CS42L42_HSDET_COMP2_LVL_MASK   (15 << CS42L42_HSDET_COMP2_LVL_SHIFT)
+
+#define CS42L42_HSDET_CTL2             (CS42L42_PAGE_11 + 0x20)
+#define CS42L42_HSDET_AUTO_TIME_SHIFT  0
+#define CS42L42_HSDET_AUTO_TIME_MASK   (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)
+#define CS42L42_HSBIAS_REF_SHIFT       3
+#define CS42L42_HSBIAS_REF_MASK                (1 << CS42L42_HSBIAS_REF_SHIFT)
+#define CS42L42_HSDET_SET_SHIFT                4
+#define CS42L42_HSDET_SET_MASK         (3 << CS42L42_HSDET_SET_SHIFT)
+#define CS42L42_HSDET_CTRL_SHIFT       6
+#define CS42L42_HSDET_CTRL_MASK                (3 << CS42L42_HSDET_CTRL_SHIFT)
+
+#define CS42L42_HS_SWITCH_CTL          (CS42L42_PAGE_11 + 0x21)
+#define CS42L42_SW_GNDHS_HS4_SHIFT     0
+#define CS42L42_SW_GNDHS_HS4_MASK      (1 << CS42L42_SW_GNDHS_HS4_SHIFT)
+#define CS42L42_SW_GNDHS_HS3_SHIFT     1
+#define CS42L42_SW_GNDHS_HS3_MASK      (1 << CS42L42_SW_GNDHS_HS3_SHIFT)
+#define CS42L42_SW_HSB_HS4_SHIFT       2
+#define CS42L42_SW_HSB_HS4_MASK                (1 << CS42L42_SW_HSB_HS4_SHIFT)
+#define CS42L42_SW_HSB_HS3_SHIFT       3
+#define CS42L42_SW_HSB_HS3_MASK                (1 << CS42L42_SW_HSB_HS3_SHIFT)
+#define CS42L42_SW_HSB_FILT_HS4_SHIFT  4
+#define CS42L42_SW_HSB_FILT_HS4_MASK   (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT)
+#define CS42L42_SW_HSB_FILT_HS3_SHIFT  5
+#define CS42L42_SW_HSB_FILT_HS3_MASK   (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT)
+#define CS42L42_SW_REF_HS4_SHIFT       6
+#define CS42L42_SW_REF_HS4_MASK                (1 << CS42L42_SW_REF_HS4_SHIFT)
+#define CS42L42_SW_REF_HS3_SHIFT       7
+#define CS42L42_SW_REF_HS3_MASK                (1 << CS42L42_SW_REF_HS3_SHIFT)
+
+#define CS42L42_HS_DET_STATUS          (CS42L42_PAGE_11 + 0x24)
+#define CS42L42_HSDET_TYPE_SHIFT       0
+#define CS42L42_HSDET_TYPE_MASK                (3 << CS42L42_HSDET_TYPE_SHIFT)
+#define CS42L42_HSDET_COMP1_OUT_SHIFT  6
+#define CS42L42_HSDET_COMP1_OUT_MASK   (1 << CS42L42_HSDET_COMP1_OUT_SHIFT)
+#define CS42L42_HSDET_COMP2_OUT_SHIFT  7
+#define CS42L42_HSDET_COMP2_OUT_MASK   (1 << CS42L42_HSDET_COMP2_OUT_SHIFT)
+#define CS42L42_PLUG_CTIA              0
+#define CS42L42_PLUG_OMTP              1
+#define CS42L42_PLUG_HEADPHONE         2
+#define CS42L42_PLUG_INVALID           3
+
+#define CS42L42_HS_CLAMP_DISABLE       (CS42L42_PAGE_11 + 0x29)
+#define CS42L42_HS_CLAMP_DISABLE_SHIFT 0
+#define CS42L42_HS_CLAMP_DISABLE_MASK  (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)
+
+/* Page 0x12 Clocking Registers */
+#define CS42L42_MCLK_SRC_SEL           (CS42L42_PAGE_12 + 0x01)
+#define CS42L42_MCLKDIV_SHIFT          1
+#define CS42L42_MCLKDIV_MASK           (1 << CS42L42_MCLKDIV_SHIFT)
+#define CS42L42_MCLK_SRC_SEL_SHIFT     0
+#define CS42L42_MCLK_SRC_SEL_MASK      (1 << CS42L42_MCLK_SRC_SEL_SHIFT)
+
+#define CS42L42_SPDIF_CLK_CFG          (CS42L42_PAGE_12 + 0x02)
+#define CS42L42_FSYNC_PW_LOWER         (CS42L42_PAGE_12 + 0x03)
+
+#define CS42L42_FSYNC_PW_UPPER                 (CS42L42_PAGE_12 + 0x04)
+#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT                0
+#define CS42L42_FSYNC_PULSE_WIDTH_MASK         (0xff << \
+                                       CS42L42_FSYNC_PULSE_WIDTH_SHIFT)
+
+#define CS42L42_FSYNC_P_LOWER          (CS42L42_PAGE_12 + 0x05)
+
+#define CS42L42_FSYNC_P_UPPER          (CS42L42_PAGE_12 + 0x06)
+#define CS42L42_FSYNC_PERIOD_SHIFT     0
+#define CS42L42_FSYNC_PERIOD_MASK      (0xff << CS42L42_FSYNC_PERIOD_SHIFT)
+
+#define CS42L42_ASP_CLK_CFG            (CS42L42_PAGE_12 + 0x07)
+#define CS42L42_ASP_SCLK_EN_SHIFT      5
+#define CS42L42_ASP_SCLK_EN_MASK       (1 << CS42L42_ASP_SCLK_EN_SHIFT)
+#define CS42L42_ASP_MASTER_MODE                0x01
+#define CS42L42_ASP_SLAVE_MODE         0x00
+#define CS42L42_ASP_MODE_SHIFT         4
+#define CS42L42_ASP_MODE_MASK          (1 << CS42L42_ASP_MODE_SHIFT)
+#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2
+#define CS42L42_ASP_SCPOL_IN_DAC_MASK  (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT)
+#define CS42L42_ASP_LCPOL_IN_SHIFT     0
+#define CS42L42_ASP_LCPOL_IN_MASK      (1 << CS42L42_ASP_LCPOL_IN_SHIFT)
+#define CS42L42_ASP_POL_INV            1
+
+#define CS42L42_ASP_FRM_CFG            (CS42L42_PAGE_12 + 0x08)
+#define CS42L42_ASP_STP_SHIFT          4
+#define CS42L42_ASP_STP_MASK           (1 << CS42L42_ASP_STP_SHIFT)
+#define CS42L42_ASP_5050_SHIFT         3
+#define CS42L42_ASP_5050_MASK          (1 << CS42L42_ASP_5050_SHIFT)
+#define CS42L42_ASP_FSD_SHIFT          0
+#define CS42L42_ASP_FSD_MASK           (7 << CS42L42_ASP_FSD_SHIFT)
+#define CS42L42_ASP_FSD_0_5            1
+#define CS42L42_ASP_FSD_1_0            2
+#define CS42L42_ASP_FSD_1_5            3
+#define CS42L42_ASP_FSD_2_0            4
+
+#define CS42L42_FS_RATE_EN             (CS42L42_PAGE_12 + 0x09)
+#define CS42L42_FS_EN_SHIFT            0
+#define CS42L42_FS_EN_MASK             (0xf << CS42L42_FS_EN_SHIFT)
+#define CS42L42_FS_EN_IASRC_96K                0x1
+#define CS42L42_FS_EN_OASRC_96K                0x2
+
+#define CS42L42_IN_ASRC_CLK            (CS42L42_PAGE_12 + 0x0A)
+#define CS42L42_CLK_IASRC_SEL_SHIFT    0
+#define CS42L42_CLK_IASRC_SEL_MASK     (1 << CS42L42_CLK_IASRC_SEL_SHIFT)
+#define CS42L42_CLK_IASRC_SEL_12       1
+
+#define CS42L42_OUT_ASRC_CLK           (CS42L42_PAGE_12 + 0x0B)
+#define CS42L42_CLK_OASRC_SEL_SHIFT    0
+#define CS42L42_CLK_OASRC_SEL_MASK     (1 << CS42L42_CLK_OASRC_SEL_SHIFT)
+#define CS42L42_CLK_OASRC_SEL_12       1
+
+#define CS42L42_PLL_DIV_CFG1           (CS42L42_PAGE_12 + 0x0C)
+#define CS42L42_SCLK_PREDIV_SHIFT      0
+#define CS42L42_SCLK_PREDIV_MASK       (3 << CS42L42_SCLK_PREDIV_SHIFT)
+
+/* Page 0x13 Interrupt Registers */
+/* Interrupts */
+#define CS42L42_ADC_OVFL_STATUS                (CS42L42_PAGE_13 + 0x01)
+#define CS42L42_MIXER_STATUS           (CS42L42_PAGE_13 + 0x02)
+#define CS42L42_SRC_STATUS             (CS42L42_PAGE_13 + 0x03)
+#define CS42L42_ASP_RX_STATUS          (CS42L42_PAGE_13 + 0x04)
+#define CS42L42_ASP_TX_STATUS          (CS42L42_PAGE_13 + 0x05)
+#define CS42L42_CODEC_STATUS           (CS42L42_PAGE_13 + 0x08)
+#define CS42L42_DET_INT_STATUS1                (CS42L42_PAGE_13 + 0x09)
+#define CS42L42_DET_INT_STATUS2                (CS42L42_PAGE_13 + 0x0A)
+#define CS42L42_SRCPL_INT_STATUS       (CS42L42_PAGE_13 + 0x0B)
+#define CS42L42_VPMON_STATUS           (CS42L42_PAGE_13 + 0x0D)
+#define CS42L42_PLL_LOCK_STATUS                (CS42L42_PAGE_13 + 0x0E)
+#define CS42L42_TSRS_PLUG_STATUS       (CS42L42_PAGE_13 + 0x0F)
+/* Masks */
+#define CS42L42_ADC_OVFL_INT_MASK      (CS42L42_PAGE_13 + 0x16)
+#define CS42L42_ADC_OVFL_SHIFT         0
+#define CS42L42_ADC_OVFL_MASK          (1 << CS42L42_ADC_OVFL_SHIFT)
+#define CS42L42_ADC_OVFL_VAL_MASK      CS42L42_ADC_OVFL_MASK
+
+#define CS42L42_MIXER_INT_MASK         (CS42L42_PAGE_13 + 0x17)
+#define CS42L42_MIX_CHB_OVFL_SHIFT     0
+#define CS42L42_MIX_CHB_OVFL_MASK      (1 << CS42L42_MIX_CHB_OVFL_SHIFT)
+#define CS42L42_MIX_CHA_OVFL_SHIFT     1
+#define CS42L42_MIX_CHA_OVFL_MASK      (1 << CS42L42_MIX_CHA_OVFL_SHIFT)
+#define CS42L42_EQ_OVFL_SHIFT          2
+#define CS42L42_EQ_OVFL_MASK           (1 << CS42L42_EQ_OVFL_SHIFT)
+#define CS42L42_EQ_BIQUAD_OVFL_SHIFT   3
+#define CS42L42_EQ_BIQUAD_OVFL_MASK    (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT)
+#define CS42L42_MIXER_VAL_MASK         (CS42L42_MIX_CHB_OVFL_MASK | \
+                                       CS42L42_MIX_CHA_OVFL_MASK | \
+                                       CS42L42_EQ_OVFL_MASK | \
+                                       CS42L42_EQ_BIQUAD_OVFL_MASK)
+
+#define CS42L42_SRC_INT_MASK           (CS42L42_PAGE_13 + 0x18)
+#define CS42L42_SRC_ILK_SHIFT          0
+#define CS42L42_SRC_ILK_MASK           (1 << CS42L42_SRC_ILK_SHIFT)
+#define CS42L42_SRC_OLK_SHIFT          1
+#define CS42L42_SRC_OLK_MASK           (1 << CS42L42_SRC_OLK_SHIFT)
+#define CS42L42_SRC_IUNLK_SHIFT                2
+#define CS42L42_SRC_IUNLK_MASK         (1 << CS42L42_SRC_IUNLK_SHIFT)
+#define CS42L42_SRC_OUNLK_SHIFT                3
+#define CS42L42_SRC_OUNLK_MASK         (1 << CS42L42_SRC_OUNLK_SHIFT)
+#define CS42L42_SRC_VAL_MASK           (CS42L42_SRC_ILK_MASK | \
+                                       CS42L42_SRC_OLK_MASK | \
+                                       CS42L42_SRC_IUNLK_MASK | \
+                                       CS42L42_SRC_OUNLK_MASK)
+
+#define CS42L42_ASP_RX_INT_MASK                (CS42L42_PAGE_13 + 0x19)
+#define CS42L42_ASPRX_NOLRCK_SHIFT     0
+#define CS42L42_ASPRX_NOLRCK_MASK      (1 << CS42L42_ASPRX_NOLRCK_SHIFT)
+#define CS42L42_ASPRX_EARLY_SHIFT      1
+#define CS42L42_ASPRX_EARLY_MASK       (1 << CS42L42_ASPRX_EARLY_SHIFT)
+#define CS42L42_ASPRX_LATE_SHIFT       2
+#define CS42L42_ASPRX_LATE_MASK                (1 << CS42L42_ASPRX_LATE_SHIFT)
+#define CS42L42_ASPRX_ERROR_SHIFT      3
+#define CS42L42_ASPRX_ERROR_MASK       (1 << CS42L42_ASPRX_ERROR_SHIFT)
+#define CS42L42_ASPRX_OVLD_SHIFT       4
+#define CS42L42_ASPRX_OVLD_MASK                (1 << CS42L42_ASPRX_OVLD_SHIFT)
+#define CS42L42_ASP_RX_VAL_MASK                (CS42L42_ASPRX_NOLRCK_MASK | \
+                                       CS42L42_ASPRX_EARLY_MASK | \
+                                       CS42L42_ASPRX_LATE_MASK | \
+                                       CS42L42_ASPRX_ERROR_MASK | \
+                                       CS42L42_ASPRX_OVLD_MASK)
+
+#define CS42L42_ASP_TX_INT_MASK                (CS42L42_PAGE_13 + 0x1A)
+#define CS42L42_ASPTX_NOLRCK_SHIFT     0
+#define CS42L42_ASPTX_NOLRCK_MASK      (1 << CS42L42_ASPTX_NOLRCK_SHIFT)
+#define CS42L42_ASPTX_EARLY_SHIFT      1
+#define CS42L42_ASPTX_EARLY_MASK       (1 << CS42L42_ASPTX_EARLY_SHIFT)
+#define CS42L42_ASPTX_LATE_SHIFT       2
+#define CS42L42_ASPTX_LATE_MASK                (1 << CS42L42_ASPTX_LATE_SHIFT)
+#define CS42L42_ASPTX_SMERROR_SHIFT    3
+#define CS42L42_ASPTX_SMERROR_MASK     (1 << CS42L42_ASPTX_SMERROR_SHIFT)
+#define CS42L42_ASP_TX_VAL_MASK                (CS42L42_ASPTX_NOLRCK_MASK | \
+                                       CS42L42_ASPTX_EARLY_MASK | \
+                                       CS42L42_ASPTX_LATE_MASK | \
+                                       CS42L42_ASPTX_SMERROR_MASK)
+
+#define CS42L42_CODEC_INT_MASK         (CS42L42_PAGE_13 + 0x1B)
+#define CS42L42_PDN_DONE_SHIFT         0
+#define CS42L42_PDN_DONE_MASK          (1 << CS42L42_PDN_DONE_SHIFT)
+#define CS42L42_HSDET_AUTO_DONE_SHIFT  1
+#define CS42L42_HSDET_AUTO_DONE_MASK   (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)
+#define CS42L42_CODEC_VAL_MASK         (CS42L42_PDN_DONE_MASK | \
+                                       CS42L42_HSDET_AUTO_DONE_MASK)
+
+#define CS42L42_SRCPL_INT_MASK         (CS42L42_PAGE_13 + 0x1C)
+#define CS42L42_SRCPL_ADC_LK_SHIFT     0
+#define CS42L42_SRCPL_ADC_LK_MASK      (1 << CS42L42_SRCPL_ADC_LK_SHIFT)
+#define CS42L42_SRCPL_DAC_LK_SHIFT     2
+#define CS42L42_SRCPL_DAC_LK_MASK      (1 << CS42L42_SRCPL_DAC_LK_SHIFT)
+#define CS42L42_SRCPL_ADC_UNLK_SHIFT   5
+#define CS42L42_SRCPL_ADC_UNLK_MASK    (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT)
+#define CS42L42_SRCPL_DAC_UNLK_SHIFT   6
+#define CS42L42_SRCPL_DAC_UNLK_MASK    (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT)
+#define CS42L42_SRCPL_VAL_MASK         (CS42L42_SRCPL_ADC_LK_MASK | \
+                                       CS42L42_SRCPL_DAC_LK_MASK | \
+                                       CS42L42_SRCPL_ADC_UNLK_MASK | \
+                                       CS42L42_SRCPL_DAC_UNLK_MASK)
+
+#define CS42L42_VPMON_INT_MASK         (CS42L42_PAGE_13 + 0x1E)
+#define CS42L42_VPMON_SHIFT            0
+#define CS42L42_VPMON_MASK             (1 << CS42L42_VPMON_SHIFT)
+#define CS42L42_VPMON_VAL_MASK         CS42L42_VPMON_MASK
+
+#define CS42L42_PLL_LOCK_INT_MASK      (CS42L42_PAGE_13 + 0x1F)
+#define CS42L42_PLL_LOCK_SHIFT         0
+#define CS42L42_PLL_LOCK_MASK          (1 << CS42L42_PLL_LOCK_SHIFT)
+#define CS42L42_PLL_LOCK_VAL_MASK      CS42L42_PLL_LOCK_MASK
+
+#define CS42L42_TSRS_PLUG_INT_MASK     (CS42L42_PAGE_13 + 0x20)
+#define CS42L42_RS_PLUG_SHIFT          0
+#define CS42L42_RS_PLUG_MASK           (1 << CS42L42_RS_PLUG_SHIFT)
+#define CS42L42_RS_UNPLUG_SHIFT                1
+#define CS42L42_RS_UNPLUG_MASK         (1 << CS42L42_RS_UNPLUG_SHIFT)
+#define CS42L42_TS_PLUG_SHIFT          2
+#define CS42L42_TS_PLUG_MASK           (1 << CS42L42_TS_PLUG_SHIFT)
+#define CS42L42_TS_UNPLUG_SHIFT                3
+#define CS42L42_TS_UNPLUG_MASK         (1 << CS42L42_TS_UNPLUG_SHIFT)
+#define CS42L42_TSRS_PLUG_VAL_MASK     (CS42L42_RS_PLUG_MASK | \
+                                       CS42L42_RS_UNPLUG_MASK | \
+                                       CS42L42_TS_PLUG_MASK | \
+                                       CS42L42_TS_UNPLUG_MASK)
+#define CS42L42_TS_PLUG                        3
+#define CS42L42_TS_UNPLUG              0
+#define CS42L42_TS_TRANS               1
+
+/* Page 0x15 Fractional-N PLL Registers */
+#define CS42L42_PLL_CTL1               (CS42L42_PAGE_15 + 0x01)
+#define CS42L42_PLL_START_SHIFT                0
+#define CS42L42_PLL_START_MASK         (1 << CS42L42_PLL_START_SHIFT)
+
+#define CS42L42_PLL_DIV_FRAC0          (CS42L42_PAGE_15 + 0x02)
+#define CS42L42_PLL_DIV_FRAC_SHIFT     0
+#define CS42L42_PLL_DIV_FRAC_MASK      (0xff << CS42L42_PLL_DIV_FRAC_SHIFT)
+
+#define CS42L42_PLL_DIV_FRAC1          (CS42L42_PAGE_15 + 0x03)
+#define CS42L42_PLL_DIV_FRAC2          (CS42L42_PAGE_15 + 0x04)
+
+#define CS42L42_PLL_DIV_INT            (CS42L42_PAGE_15 + 0x05)
+#define CS42L42_PLL_DIV_INT_SHIFT      0
+#define CS42L42_PLL_DIV_INT_MASK       (0xff << CS42L42_PLL_DIV_INT_SHIFT)
+
+#define CS42L42_PLL_CTL3               (CS42L42_PAGE_15 + 0x08)
+#define CS42L42_PLL_DIVOUT_SHIFT       0
+#define CS42L42_PLL_DIVOUT_MASK                (0xff << CS42L42_PLL_DIVOUT_SHIFT)
+
+#define CS42L42_PLL_CAL_RATIO          (CS42L42_PAGE_15 + 0x0A)
+#define CS42L42_PLL_CAL_RATIO_SHIFT    0
+#define CS42L42_PLL_CAL_RATIO_MASK     (0xff << CS42L42_PLL_CAL_RATIO_SHIFT)
+
+#define CS42L42_PLL_CTL4               (CS42L42_PAGE_15 + 0x1B)
+#define CS42L42_PLL_MODE_SHIFT         0
+#define CS42L42_PLL_MODE_MASK          (3 << CS42L42_PLL_MODE_SHIFT)
+
+/* Page 0x19 HP Load Detect Registers */
+#define CS42L42_LOAD_DET_RCSTAT                (CS42L42_PAGE_19 + 0x25)
+#define CS42L42_RLA_STAT_SHIFT         0
+#define CS42L42_RLA_STAT_MASK          (3 << CS42L42_RLA_STAT_SHIFT)
+#define CS42L42_RLA_STAT_15_OHM                0
+
+#define CS42L42_LOAD_DET_DONE          (CS42L42_PAGE_19 + 0x26)
+#define CS42L42_HPLOAD_DET_DONE_SHIFT  0
+#define CS42L42_HPLOAD_DET_DONE_MASK   (1 << CS42L42_HPLOAD_DET_DONE_SHIFT)
+
+#define CS42L42_LOAD_DET_EN            (CS42L42_PAGE_19 + 0x27)
+#define CS42L42_HP_LD_EN_SHIFT         0
+#define CS42L42_HP_LD_EN_MASK          (1 << CS42L42_HP_LD_EN_SHIFT)
+
+/* Page 0x1B Headset Interface Registers */
+#define CS42L42_HSBIAS_SC_AUTOCTL              (CS42L42_PAGE_1B + 0x70)
+#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT                0
+#define CS42L42_HSBIAS_SENSE_TRIP_MASK         (7 << \
+                                       CS42L42_HSBIAS_SENSE_TRIP_SHIFT)
+#define CS42L42_TIP_SENSE_EN_SHIFT             5
+#define CS42L42_TIP_SENSE_EN_MASK              (1 << \
+                                       CS42L42_TIP_SENSE_EN_SHIFT)
+#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT          6
+#define CS42L42_AUTO_HSBIAS_HIZ_MASK           (1 << \
+                                       CS42L42_AUTO_HSBIAS_HIZ_SHIFT)
+#define CS42L42_HSBIAS_SENSE_EN_SHIFT          7
+#define CS42L42_HSBIAS_SENSE_EN_MASK           (1 << \
+                                       CS42L42_HSBIAS_SENSE_EN_SHIFT)
+
+#define CS42L42_WAKE_CTL               (CS42L42_PAGE_1B + 0x71)
+#define CS42L42_WAKEB_CLEAR_SHIFT      0
+#define CS42L42_WAKEB_CLEAR_MASK       (1 << CS42L42_WAKEB_CLEAR_SHIFT)
+#define CS42L42_WAKEB_MODE_SHIFT       5
+#define CS42L42_WAKEB_MODE_MASK                (1 << CS42L42_WAKEB_MODE_SHIFT)
+#define CS42L42_M_HP_WAKE_SHIFT                6
+#define CS42L42_M_HP_WAKE_MASK         (1 << CS42L42_M_HP_WAKE_SHIFT)
+#define CS42L42_M_MIC_WAKE_SHIFT       7
+#define CS42L42_M_MIC_WAKE_MASK                (1 << CS42L42_M_MIC_WAKE_SHIFT)
+
+#define CS42L42_ADC_DISABLE_MUTE               (CS42L42_PAGE_1B + 0x72)
+#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT      7
+#define CS42L42_ADC_DISABLE_S0_MUTE_MASK       (1 << \
+                                       CS42L42_ADC_DISABLE_S0_MUTE_SHIFT)
+
+#define CS42L42_TIPSENSE_CTL                   (CS42L42_PAGE_1B + 0x73)
+#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT       0
+#define CS42L42_TIP_SENSE_DEBOUNCE_MASK                (3 << \
+                                       CS42L42_TIP_SENSE_DEBOUNCE_SHIFT)
+#define CS42L42_TIP_SENSE_INV_SHIFT            5
+#define CS42L42_TIP_SENSE_INV_MASK             (1 << \
+                                       CS42L42_TIP_SENSE_INV_SHIFT)
+#define CS42L42_TIP_SENSE_CTRL_SHIFT           6
+#define CS42L42_TIP_SENSE_CTRL_MASK            (3 << \
+                                       CS42L42_TIP_SENSE_CTRL_SHIFT)
+
+#define CS42L42_MISC_DET_CTL           (CS42L42_PAGE_1B + 0x74)
+#define CS42L42_PDN_MIC_LVL_DET_SHIFT  0
+#define CS42L42_PDN_MIC_LVL_DET_MASK   (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)
+#define CS42L42_HSBIAS_CTL_SHIFT       1
+#define CS42L42_HSBIAS_CTL_MASK                (3 << CS42L42_HSBIAS_CTL_SHIFT)
+#define CS42L42_DETECT_MODE_SHIFT      3
+#define CS42L42_DETECT_MODE_MASK       (3 << CS42L42_DETECT_MODE_SHIFT)
+
+#define CS42L42_MIC_DET_CTL1           (CS42L42_PAGE_1B + 0x75)
+#define CS42L42_HS_DET_LEVEL_SHIFT     0
+#define CS42L42_HS_DET_LEVEL_MASK      (0x3F << CS42L42_HS_DET_LEVEL_SHIFT)
+#define CS42L42_EVENT_STAT_SEL_SHIFT   6
+#define CS42L42_EVENT_STAT_SEL_MASK    (1 << CS42L42_EVENT_STAT_SEL_SHIFT)
+#define CS42L42_LATCH_TO_VP_SHIFT      7
+#define CS42L42_LATCH_TO_VP_MASK       (1 << CS42L42_LATCH_TO_VP_SHIFT)
+
+#define CS42L42_MIC_DET_CTL2           (CS42L42_PAGE_1B + 0x76)
+#define CS42L42_DEBOUNCE_TIME_SHIFT    5
+#define CS42L42_DEBOUNCE_TIME_MASK     (0x07 << CS42L42_DEBOUNCE_TIME_SHIFT)
+
+#define CS42L42_DET_STATUS1            (CS42L42_PAGE_1B + 0x77)
+#define CS42L42_HSBIAS_HIZ_MODE_SHIFT  6
+#define CS42L42_HSBIAS_HIZ_MODE_MASK   (1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT)
+#define CS42L42_TIP_SENSE_SHIFT                7
+#define CS42L42_TIP_SENSE_MASK         (1 << CS42L42_TIP_SENSE_SHIFT)
+
+#define CS42L42_DET_STATUS2            (CS42L42_PAGE_1B + 0x78)
+#define CS42L42_SHORT_TRUE_SHIFT       0
+#define CS42L42_SHORT_TRUE_MASK                (1 << CS42L42_SHORT_TRUE_SHIFT)
+#define CS42L42_HS_TRUE_SHIFT  1
+#define CS42L42_HS_TRUE_MASK           (1 << CS42L42_HS_TRUE_SHIFT)
+
+#define CS42L42_DET_INT1_MASK          (CS42L42_PAGE_1B + 0x79)
+#define CS42L42_TIP_SENSE_UNPLUG_SHIFT 5
+#define CS42L42_TIP_SENSE_UNPLUG_MASK  (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT)
+#define CS42L42_TIP_SENSE_PLUG_SHIFT   6
+#define CS42L42_TIP_SENSE_PLUG_MASK    (1 << CS42L42_TIP_SENSE_PLUG_SHIFT)
+#define CS42L42_HSBIAS_SENSE_SHIFT     7
+#define CS42L42_HSBIAS_SENSE_MASK      (1 << CS42L42_HSBIAS_SENSE_SHIFT)
+#define CS42L42_DET_INT_VAL1_MASK      (CS42L42_TIP_SENSE_UNPLUG_MASK | \
+                                       CS42L42_TIP_SENSE_PLUG_MASK | \
+                                       CS42L42_HSBIAS_SENSE_MASK)
+
+#define CS42L42_DET_INT2_MASK          (CS42L42_PAGE_1B + 0x7A)
+#define CS42L42_M_SHORT_DET_SHIFT      0
+#define CS42L42_M_SHORT_DET_MASK       (1 << \
+                                       CS42L42_M_SHORT_DET_SHIFT)
+#define CS42L42_M_SHORT_RLS_SHIFT      1
+#define CS42L42_M_SHORT_RLS_MASK       (1 << \
+                                       CS42L42_M_SHORT_RLS_SHIFT)
+#define CS42L42_M_HSBIAS_HIZ_SHIFT     2
+#define CS42L42_M_HSBIAS_HIZ_MASK      (1 << \
+                                       CS42L42_M_HSBIAS_HIZ_SHIFT)
+#define CS42L42_M_DETECT_FT_SHIFT      6
+#define CS42L42_M_DETECT_FT_MASK       (1 << \
+                                       CS42L42_M_DETECT_FT_SHIFT)
+#define CS42L42_M_DETECT_TF_SHIFT      7
+#define CS42L42_M_DETECT_TF_MASK       (1 << \
+                                       CS42L42_M_DETECT_TF_SHIFT)
+#define CS42L42_DET_INT_VAL2_MASK      (CS42L42_M_SHORT_DET_MASK | \
+                                       CS42L42_M_SHORT_RLS_MASK | \
+                                       CS42L42_M_HSBIAS_HIZ_MASK | \
+                                       CS42L42_M_DETECT_FT_MASK | \
+                                       CS42L42_M_DETECT_TF_MASK)
+
+/* Page 0x1C Headset Bias Registers */
+#define CS42L42_HS_BIAS_CTL            (CS42L42_PAGE_1C + 0x03)
+#define CS42L42_HSBIAS_RAMP_SHIFT      0
+#define CS42L42_HSBIAS_RAMP_MASK       (3 << CS42L42_HSBIAS_RAMP_SHIFT)
+#define CS42L42_HSBIAS_PD_SHIFT                4
+#define CS42L42_HSBIAS_PD_MASK         (1 << CS42L42_HSBIAS_PD_SHIFT)
+#define CS42L42_HSBIAS_CAPLESS_SHIFT   7
+#define CS42L42_HSBIAS_CAPLESS_MASK    (1 << CS42L42_HSBIAS_CAPLESS_SHIFT)
+
+/* Page 0x1D ADC Registers */
+#define CS42L42_ADC_CTL                        (CS42L42_PAGE_1D + 0x01)
+#define CS42L42_ADC_NOTCH_DIS_SHIFT            5
+#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT       4
+#define CS42L42_ADC_INV_SHIFT                  2
+#define CS42L42_ADC_DIG_BOOST_SHIFT            0
+
+#define CS42L42_ADC_VOLUME             (CS42L42_PAGE_1D + 0x03)
+#define CS42L42_ADC_VOL_SHIFT          0
+
+#define CS42L42_ADC_WNF_HPF_CTL                (CS42L42_PAGE_1D + 0x04)
+#define CS42L42_ADC_WNF_CF_SHIFT       4
+#define CS42L42_ADC_WNF_EN_SHIFT       3
+#define CS42L42_ADC_HPF_CF_SHIFT       1
+#define CS42L42_ADC_HPF_EN_SHIFT       0
+
+/* Page 0x1F DAC Registers */
+#define CS42L42_DAC_CTL1               (CS42L42_PAGE_1F + 0x01)
+#define CS42L42_DACB_INV_SHIFT         1
+#define CS42L42_DACA_INV_SHIFT         0
+
+#define CS42L42_DAC_CTL2               (CS42L42_PAGE_1F + 0x06)
+#define CS42L42_HPOUT_PULLDOWN_SHIFT   4
+#define CS42L42_HPOUT_PULLDOWN_MASK    (15 << CS42L42_HPOUT_PULLDOWN_SHIFT)
+#define CS42L42_HPOUT_LOAD_SHIFT       3
+#define CS42L42_HPOUT_LOAD_MASK                (1 << CS42L42_HPOUT_LOAD_SHIFT)
+#define CS42L42_HPOUT_CLAMP_SHIFT      2
+#define CS42L42_HPOUT_CLAMP_MASK       (1 << CS42L42_HPOUT_CLAMP_SHIFT)
+#define CS42L42_DAC_HPF_EN_SHIFT       1
+#define CS42L42_DAC_HPF_EN_MASK                (1 << CS42L42_DAC_HPF_EN_SHIFT)
+#define CS42L42_DAC_MON_EN_SHIFT       0
+#define CS42L42_DAC_MON_EN_MASK                (1 << CS42L42_DAC_MON_EN_SHIFT)
+
+/* Page 0x20 HP CTL Registers */
+#define CS42L42_HP_CTL                 (CS42L42_PAGE_20 + 0x01)
+#define CS42L42_HP_ANA_BMUTE_SHIFT     3
+#define CS42L42_HP_ANA_BMUTE_MASK      (1 << CS42L42_HP_ANA_BMUTE_SHIFT)
+#define CS42L42_HP_ANA_AMUTE_SHIFT     2
+#define CS42L42_HP_ANA_AMUTE_MASK      (1 << CS42L42_HP_ANA_AMUTE_SHIFT)
+#define CS42L42_HP_FULL_SCALE_VOL_SHIFT        1
+#define CS42L42_HP_FULL_SCALE_VOL_MASK (1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT)
+
+/* Page 0x21 Class H Registers */
+#define CS42L42_CLASSH_CTL             (CS42L42_PAGE_21 + 0x01)
+
+/* Page 0x23 Mixer Volume Registers */
+#define CS42L42_MIXER_CHA_VOL          (CS42L42_PAGE_23 + 0x01)
+#define CS42L42_MIXER_ADC_VOL          (CS42L42_PAGE_23 + 0x02)
+
+#define CS42L42_MIXER_CHB_VOL          (CS42L42_PAGE_23 + 0x03)
+#define CS42L42_MIXER_CH_VOL_SHIFT     0
+#define CS42L42_MIXER_CH_VOL_MASK      (0x3f << CS42L42_MIXER_CH_VOL_SHIFT)
+
+/* Page 0x24 EQ Registers */
+#define CS42L42_EQ_COEF_IN0            (CS42L42_PAGE_24 + 0x01)
+#define CS42L42_EQ_COEF_IN1            (CS42L42_PAGE_24 + 0x02)
+#define CS42L42_EQ_COEF_IN2            (CS42L42_PAGE_24 + 0x03)
+#define CS42L42_EQ_COEF_IN3            (CS42L42_PAGE_24 + 0x04)
+#define CS42L42_EQ_COEF_RW             (CS42L42_PAGE_24 + 0x06)
+#define CS42L42_EQ_COEF_OUT0           (CS42L42_PAGE_24 + 0x07)
+#define CS42L42_EQ_COEF_OUT1           (CS42L42_PAGE_24 + 0x08)
+#define CS42L42_EQ_COEF_OUT2           (CS42L42_PAGE_24 + 0x09)
+#define CS42L42_EQ_COEF_OUT3           (CS42L42_PAGE_24 + 0x0A)
+#define CS42L42_EQ_INIT_STAT           (CS42L42_PAGE_24 + 0x0B)
+#define CS42L42_EQ_START_FILT          (CS42L42_PAGE_24 + 0x0C)
+#define CS42L42_EQ_MUTE_CTL            (CS42L42_PAGE_24 + 0x0E)
+
+/* Page 0x25 Audio Port Registers */
+#define CS42L42_SP_RX_CH_SEL           (CS42L42_PAGE_25 + 0x01)
+
+#define CS42L42_SP_RX_ISOC_CTL         (CS42L42_PAGE_25 + 0x02)
+#define CS42L42_SP_RX_RSYNC_SHIFT      6
+#define CS42L42_SP_RX_RSYNC_MASK       (1 << CS42L42_SP_RX_RSYNC_SHIFT)
+#define CS42L42_SP_RX_NSB_POS_SHIFT    3
+#define CS42L42_SP_RX_NSB_POS_MASK     (7 << CS42L42_SP_RX_NSB_POS_SHIFT)
+#define CS42L42_SP_RX_NFS_NSBB_SHIFT   2
+#define CS42L42_SP_RX_NFS_NSBB_MASK    (1 << CS42L42_SP_RX_NFS_NSBB_SHIFT)
+#define CS42L42_SP_RX_ISOC_MODE_SHIFT  0
+#define CS42L42_SP_RX_ISOC_MODE_MASK   (3 << CS42L42_SP_RX_ISOC_MODE_SHIFT)
+
+#define CS42L42_SP_RX_FS               (CS42L42_PAGE_25 + 0x03)
+#define CS42l42_SPDIF_CH_SEL           (CS42L42_PAGE_25 + 0x04)
+#define CS42L42_SP_TX_ISOC_CTL         (CS42L42_PAGE_25 + 0x05)
+#define CS42L42_SP_TX_FS               (CS42L42_PAGE_25 + 0x06)
+#define CS42L42_SPDIF_SW_CTL1          (CS42L42_PAGE_25 + 0x07)
+
+/* Page 0x26 SRC Registers */
+#define CS42L42_SRC_SDIN_FS            (CS42L42_PAGE_26 + 0x01)
+#define CS42L42_SRC_SDIN_FS_SHIFT      0
+#define CS42L42_SRC_SDIN_FS_MASK       (0x1f << CS42L42_SRC_SDIN_FS_SHIFT)
+
+#define CS42L42_SRC_SDOUT_FS           (CS42L42_PAGE_26 + 0x09)
+
+/* Page 0x28 S/PDIF Registers */
+#define CS42L42_SPDIF_CTL1             (CS42L42_PAGE_28 + 0x01)
+#define CS42L42_SPDIF_CTL2             (CS42L42_PAGE_28 + 0x02)
+#define CS42L42_SPDIF_CTL3             (CS42L42_PAGE_28 + 0x03)
+#define CS42L42_SPDIF_CTL4             (CS42L42_PAGE_28 + 0x04)
+
+/* Page 0x29 Serial Port TX Registers */
+#define CS42L42_ASP_TX_SZ_EN           (CS42L42_PAGE_29 + 0x01)
+#define CS42L42_ASP_TX_CH_EN           (CS42L42_PAGE_29 + 0x02)
+#define CS42L42_ASP_TX_CH_AP_RES       (CS42L42_PAGE_29 + 0x03)
+#define CS42L42_ASP_TX_CH1_BIT_MSB     (CS42L42_PAGE_29 + 0x04)
+#define CS42L42_ASP_TX_CH1_BIT_LSB     (CS42L42_PAGE_29 + 0x05)
+#define CS42L42_ASP_TX_HIZ_DLY_CFG     (CS42L42_PAGE_29 + 0x06)
+#define CS42L42_ASP_TX_CH2_BIT_MSB     (CS42L42_PAGE_29 + 0x0A)
+#define CS42L42_ASP_TX_CH2_BIT_LSB     (CS42L42_PAGE_29 + 0x0B)
+
+/* Page 0x2A Serial Port RX Registers */
+#define CS42L42_ASP_RX_DAI0_EN         (CS42L42_PAGE_2A + 0x01)
+#define CS42L42_ASP_RX0_CH_EN_SHIFT    2
+#define CS42L42_ASP_RX0_CH_EN_MASK     (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT)
+#define CS42L42_ASP_RX0_CH1_EN         1
+#define CS42L42_ASP_RX0_CH2_EN         2
+#define CS42L42_ASP_RX0_CH3_EN         4
+#define CS42L42_ASP_RX0_CH4_EN         8
+
+#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02)
+#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB        (CS42L42_PAGE_2A + 0x03)
+#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB        (CS42L42_PAGE_2A + 0x04)
+#define CS42L42_ASP_RX_DAI0_CH2_AP_RES (CS42L42_PAGE_2A + 0x05)
+#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB        (CS42L42_PAGE_2A + 0x06)
+#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB        (CS42L42_PAGE_2A + 0x07)
+#define CS42L42_ASP_RX_DAI0_CH3_AP_RES (CS42L42_PAGE_2A + 0x08)
+#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB        (CS42L42_PAGE_2A + 0x09)
+#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB        (CS42L42_PAGE_2A + 0x0A)
+#define CS42L42_ASP_RX_DAI0_CH4_AP_RES (CS42L42_PAGE_2A + 0x0B)
+#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB        (CS42L42_PAGE_2A + 0x0C)
+#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB        (CS42L42_PAGE_2A + 0x0D)
+#define CS42L42_ASP_RX_DAI1_CH1_AP_RES (CS42L42_PAGE_2A + 0x0E)
+#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB        (CS42L42_PAGE_2A + 0x0F)
+#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB        (CS42L42_PAGE_2A + 0x10)
+#define CS42L42_ASP_RX_DAI1_CH2_AP_RES (CS42L42_PAGE_2A + 0x11)
+#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB        (CS42L42_PAGE_2A + 0x12)
+#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB        (CS42L42_PAGE_2A + 0x13)
+
+#define CS42L42_ASP_RX_CH_AP_SHIFT     6
+#define CS42L42_ASP_RX_CH_AP_MASK      (1 << CS42L42_ASP_RX_CH_AP_SHIFT)
+#define CS42L42_ASP_RX_CH_AP_LOW       0
+#define CS42L42_ASP_RX_CH_AP_HI                1
+#define CS42L42_ASP_RX_CH_RES_SHIFT    0
+#define CS42L42_ASP_RX_CH_RES_MASK     (3 << CS42L42_ASP_RX_CH_RES_SHIFT)
+#define CS42L42_ASP_RX_CH_RES_32       3
+#define CS42L42_ASP_RX_CH_RES_16       1
+#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT 0
+#define CS42L42_ASP_RX_CH_BIT_ST_MASK  (0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT)
+
+/* Page 0x30 ID Registers */
+#define CS42L42_SUB_REVID              (CS42L42_PAGE_30 + 0x14)
+#define CS42L42_MAX_REGISTER           (CS42L42_PAGE_30 + 0x14)
+
+/* Defines for fracturing values spread across multiple registers */
+#define CS42L42_FRAC0_VAL(val) ((val) & 0x0000ff)
+#define CS42L42_FRAC1_VAL(val) (((val) & 0x00ff00) >> 8)
+#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16)
+
+#define CS42L42_NUM_SUPPLIES   5
+
+static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
+       "VA",
+       "VP",
+       "VCP",
+       "VD_FILT",
+       "VL",
+};
+
+struct  cs42l42_private {
+       struct regmap *regmap;
+       struct snd_soc_codec *codec;
+       struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES];
+       struct gpio_desc *reset_gpio;
+       struct completion pdn_done;
+       u32 sclk;
+       u32 srate;
+       u32 swidth;
+       u8 plug_state;
+       u8 hs_type;
+       u8 ts_inv;
+       u8 ts_dbnc_rise;
+       u8 ts_dbnc_fall;
+       u8 btn_det_init_dbnce;
+       u8 btn_det_event_dbnce;
+       u8 bias_thresholds[CS42L42_NUM_BIASES];
+       u8 hs_bias_ramp_rate;
+       u8 hs_bias_ramp_time;
+};
+
+#endif /* __CS42L42_H__ */
index 54c1768bc81859f5f2a66cc7388ac272879c236a..cb6ca85f15362cca9d11a1dfe9519f012dd82466 100644 (file)
@@ -64,8 +64,6 @@ struct  cs42l56_private {
 };
 
 static const struct reg_default cs42l56_reg_defaults[] = {
-       { 1, 0x56 },    /* r01  - ID 1 */
-       { 2, 0x04 },    /* r02  - ID 2 */
        { 3, 0x7f },    /* r03  - Power Ctl 1 */
        { 4, 0xff },    /* r04  - Power Ctl 2 */
        { 5, 0x00 },    /* ro5  - Clocking Ctl 1 */
@@ -1262,8 +1260,6 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
                return ret;
        }
 
-       regcache_cache_bypass(cs42l56->regmap, true);
-
        ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
        devid = reg & CS42L56_CHIP_ID_MASK;
        if (devid != CS42L56_DEVID) {
@@ -1279,23 +1275,25 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
        dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
                 alpha_rev, metal_rev);
 
-       regcache_cache_bypass(cs42l56->regmap, false);
-
        if (cs42l56->pdata.ain1a_ref_cfg)
                regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
-                                  CS42L56_AIN1A_REF_MASK, 1);
+                                  CS42L56_AIN1A_REF_MASK,
+                                  CS42L56_AIN1A_REF_MASK);
 
        if (cs42l56->pdata.ain1b_ref_cfg)
                regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
-                                  CS42L56_AIN1B_REF_MASK, 1);
+                                  CS42L56_AIN1B_REF_MASK,
+                                  CS42L56_AIN1B_REF_MASK);
 
        if (cs42l56->pdata.ain2a_ref_cfg)
                regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
-                                  CS42L56_AIN2A_REF_MASK, 1);
+                                  CS42L56_AIN2A_REF_MASK,
+                                  CS42L56_AIN2A_REF_MASK);
 
        if (cs42l56->pdata.ain2b_ref_cfg)
                regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
-                                  CS42L56_AIN2B_REF_MASK, 1);
+                                  CS42L56_AIN2B_REF_MASK,
+                                  CS42L56_AIN2B_REF_MASK);
 
        if (cs42l56->pdata.micbias_lvl)
                regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
index 71ba5605495fc15c5fc267fc1daa9b2631569e10..3df2c473ab8834cd27d0f8daa732aaacc3526144 100644 (file)
@@ -1337,8 +1337,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
                gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
        }
 
-       regcache_cache_bypass(cs42l73->regmap, true);
-
        /* initialize codec */
        ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg);
        devid = (reg & 0xFF) << 12;
@@ -1366,8 +1364,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
        dev_info(&i2c_client->dev,
                 "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
 
-       regcache_cache_bypass(cs42l73->regmap, false);
-
        ret =  snd_soc_register_codec(&i2c_client->dev,
                        &soc_codec_dev_cs42l73, cs42l73_dai,
                        ARRAY_SIZE(cs42l73_dai));
index b4d87379d2bcba6ae490bce1198edda6f57f5f20..c1785bd4ff199fca82ad331abc273707793cd6cd 100644 (file)
@@ -321,7 +321,6 @@ static struct snd_soc_dai_driver cs42xx8_dai = {
 };
 
 static const struct reg_default cs42xx8_reg[] = {
-       { 0x01, 0x01 },   /* Chip I.D. and Revision Register */
        { 0x02, 0x00 },   /* Power Control */
        { 0x03, 0xF0 },   /* Functional Mode */
        { 0x04, 0x46 },   /* Interface Formats */
@@ -498,13 +497,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
        /* Make sure hardware reset done */
        msleep(5);
 
-       /*
-        * We haven't marked the chip revision as volatile due to
-        * sharing a register with the right input volume; explicitly
-        * bypass the cache to read it.
-        */
-       regcache_cache_bypass(cs42xx8->regmap, true);
-
        /* Validate the chip ID */
        ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
        if (ret < 0) {
@@ -523,8 +515,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
        dev_info(dev, "found device, revision %X\n",
                        val & CS42XX8_CHIPID_REV_ID_MASK);
 
-       regcache_cache_bypass(cs42xx8->regmap, false);
-
        cs42xx8_dai.name = cs42xx8->drvdata->name;
 
        /* Each adc supports stereo input */
index 5b22564f037cf9367dfb0fd82915d58fbee78db5..73559ae864b656aa224564a089bd336fd9b39dc4 100644 (file)
@@ -335,9 +335,11 @@ static const struct snd_kcontrol_new cs47l24_aec_loopback_mux =
 
 static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
-                   ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
+                   ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
-                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
                    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
@@ -1064,7 +1066,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
 static int cs47l24_open(struct snd_compr_stream *stream)
 {
        struct snd_soc_pcm_runtime *rtd = stream->private_data;
-       struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+       struct cs47l24_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
        struct arizona *arizona = priv->core.arizona;
        int n_adsp;
 
@@ -1113,8 +1115,8 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
 static int cs47l24_codec_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->core.arizona;
        int ret;
 
        priv->core.arizona->dapm = dapm;
@@ -1124,14 +1126,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
        arizona_init_mono(codec);
        arizona_init_notifiers(codec);
 
-       ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
-                                 "ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
-                                 priv);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
-               return ret;
-       }
-
        ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
        if (ret)
                goto err_adsp2_codec_probe;
@@ -1145,7 +1139,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
        if (ret)
                goto err_adsp2_codec_probe;
 
-       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+       snd_soc_component_disable_pin(component, "HAPTICS");
 
        return 0;
 
@@ -1159,17 +1153,12 @@ err_adsp2_codec_probe:
 static int cs47l24_codec_remove(struct snd_soc_codec *codec)
 {
        struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->core.arizona;
 
        wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
        wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
 
        priv->core.arizona->dapm = NULL;
 
-       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
-
-       arizona_free_spk(codec);
-
        return 0;
 }
 
@@ -1285,25 +1274,47 @@ static int cs47l24_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
 
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+                                 "ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
+                                 cs47l24);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
+               return ret;
+       }
+
+       ret = arizona_init_spk_irqs(arizona);
+       if (ret < 0)
+               goto err_dsp_irq;
+
        ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
-               return ret;
+               goto err_spk_irqs;
        }
 
        ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
                                      cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
-               snd_soc_unregister_platform(&pdev->dev);
+               goto err_platform;
        }
 
+       return ret;
+
+err_platform:
+       snd_soc_unregister_platform(&pdev->dev);
+err_spk_irqs:
+       arizona_free_spk_irqs(arizona);
+err_dsp_irq:
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
+
        return ret;
 }
 
 static int cs47l24_remove(struct platform_device *pdev)
 {
        struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev);
+       struct arizona *arizona = cs47l24->core.arizona;
 
        snd_soc_unregister_platform(&pdev->dev);
        snd_soc_unregister_codec(&pdev->dev);
@@ -1312,6 +1323,10 @@ static int cs47l24_remove(struct platform_device *pdev)
        wm_adsp2_remove(&cs47l24->core.adsp[1]);
        wm_adsp2_remove(&cs47l24->core.adsp[2]);
 
+       arizona_free_spk_irqs(arizona);
+
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
+
        return 0;
 }
 
index 2b8914dd59908897cdabfcb5abfd8f757cabfaf7..6274d79c1353ed1ad342aeabf0b523d970c721ff 100644 (file)
@@ -204,10 +204,19 @@ static void da7219_aad_hptest_work(struct work_struct *work)
        snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL,
                            DA7219_MIXOUT_R_AMP_EN_MASK,
                            DA7219_MIXOUT_R_AMP_EN_MASK);
-       snd_soc_write(codec, DA7219_HP_L_CTRL,
-                     DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
-       snd_soc_write(codec, DA7219_HP_R_CTRL,
-                     DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK,
+                           DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK,
+                           DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK);
+       msleep(DA7219_SETTLING_DELAY);
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_MUTE_EN_MASK |
+                           DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_MUTE_EN_MASK |
+                           DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0);
 
        /*
         * If we're running from the internal oscillator then give audio paths
@@ -244,6 +253,7 @@ static void da7219_aad_hptest_work(struct work_struct *work)
        regcache_mark_dirty(da7219->regmap);
        regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL,
                             DA7219_HP_R_CTRL);
+       msleep(DA7219_SETTLING_DELAY);
        regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL,
                             DA7219_MIXOUT_R_CTRL);
        regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L,
index 1152aa5e7c394208d6e42f04a2c4d44c8b0ea906..99601627f83cf6fe0dc83249139058ce6b15611e 100644 (file)
@@ -823,6 +823,85 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
        }
 }
 
+static int da7219_settling_event(struct snd_soc_dapm_widget *w,
+                                struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               msleep(DA7219_SETTLING_DELAY);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int da7219_mixout_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);
+       u8 hp_ctrl, min_gain_mask;
+
+       switch (w->reg) {
+       case DA7219_MIXOUT_L_CTRL:
+               hp_ctrl = DA7219_HP_L_CTRL;
+               min_gain_mask = DA7219_HP_L_AMP_MIN_GAIN_EN_MASK;
+               break;
+       case DA7219_MIXOUT_R_CTRL:
+               hp_ctrl = DA7219_HP_R_CTRL;
+               min_gain_mask = DA7219_HP_R_AMP_MIN_GAIN_EN_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Enable minimum gain on HP to avoid pops */
+               snd_soc_update_bits(codec, hp_ctrl, min_gain_mask,
+                                   min_gain_mask);
+
+               msleep(DA7219_MIN_GAIN_DELAY);
+
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               /* Remove minimum gain on HP */
+               snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, 0);
+
+               break;
+       }
+
+       return 0;
+}
+
+static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_PRE_PMD:
+               /* Ensure nominal gain ramping for DAPM sequence */
+               da7219->gain_ramp_ctrl =
+                       snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL);
+               snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+                             DA7219_GAIN_RAMP_RATE_NOMINAL);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               /* Restore previous gain ramp settings */
+               snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL,
+                             da7219->gain_ramp_ctrl);
+               break;
+       }
+
+       return 0;
+}
+
 
 /*
  * DAPM Widgets
@@ -880,7 +959,8 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* DAI */
-       SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7219_DAI_TDM_CTRL,
+                            DA7219_DAI_OE_SHIFT, DA7219_NO_INVERT),
        SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
 
        /* Output Muxes */
@@ -906,30 +986,46 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
                           ARRAY_SIZE(da7219_st_out_filtr_mix_controls)),
 
        /* DACs */
-       SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT,
-                        DA7219_NO_INVERT),
-       SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT,
-                        DA7219_NO_INVERT),
+       SND_SOC_DAPM_DAC_E("DACL", NULL, DA7219_DAC_L_CTRL,
+                          DA7219_DAC_L_EN_SHIFT, DA7219_NO_INVERT,
+                          da7219_settling_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_DAC_E("DACR", NULL, DA7219_DAC_R_CTRL,
+                          DA7219_DAC_R_EN_SHIFT, DA7219_NO_INVERT,
+                          da7219_settling_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* Output PGAs */
-       SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
-                        DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
-                        NULL, 0),
-       SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
-                        DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
-                        NULL, 0),
-       SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL,
-                        DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
-       SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL,
-                        DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0),
+       SND_SOC_DAPM_PGA_E("Mixout Left PGA", DA7219_MIXOUT_L_CTRL,
+                          DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                          NULL, 0, da7219_mixout_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_PGA_E("Mixout Right PGA", DA7219_MIXOUT_R_CTRL,
+                          DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                          NULL, 0, da7219_mixout_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_SUPPLY_S("Headphone Left PGA", 1, DA7219_HP_L_CTRL,
+                             DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                             da7219_settling_event,
+                             SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("Headphone Right PGA", 1, DA7219_HP_R_CTRL,
+                             DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT,
+                             da7219_settling_event,
+                             SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* Output Supplies */
-       SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT,
-                           DA7219_NO_INVERT, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("Charge Pump", 0, DA7219_CP_CTRL,
+                             DA7219_CP_EN_SHIFT, DA7219_NO_INVERT,
+                             da7219_settling_event,
+                             SND_SOC_DAPM_POST_PMU),
 
        /* Outputs */
        SND_SOC_DAPM_OUTPUT("HPL"),
        SND_SOC_DAPM_OUTPUT("HPR"),
+
+       /* Pre/Post Power */
+       SND_SOC_DAPM_PRE("Pre Power Gain Ramp", da7219_gain_ramp_event),
+       SND_SOC_DAPM_POST("Post Power Gain Ramp", da7219_gain_ramp_event),
 };
 
 
@@ -1002,8 +1098,8 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = {
        {"Mixout Left PGA", NULL, "DACL"},
        {"Mixout Right PGA", NULL, "DACR"},
 
-       {"Headphone Left PGA", NULL, "Mixout Left PGA"},
-       {"Headphone Right PGA", NULL, "Mixout Right PGA"},
+       {"HPL", NULL, "Mixout Left PGA"},
+       {"HPR", NULL, "Mixout Right PGA"},
 
        {"HPL", NULL, "Headphone Left PGA"},
        {"HPR", NULL, "Headphone Right PGA"},
@@ -1711,6 +1807,14 @@ static int da7219_probe(struct snd_soc_codec *codec)
                            DA7219_HP_R_AMP_RAMP_EN_MASK,
                            DA7219_HP_R_AMP_RAMP_EN_MASK);
 
+       /* Default minimum gain on HP to avoid pops during DAPM sequencing */
+       snd_soc_update_bits(codec, DA7219_HP_L_CTRL,
+                           DA7219_HP_L_AMP_MIN_GAIN_EN_MASK,
+                           DA7219_HP_L_AMP_MIN_GAIN_EN_MASK);
+       snd_soc_update_bits(codec, DA7219_HP_R_CTRL,
+                           DA7219_HP_R_AMP_MIN_GAIN_EN_MASK,
+                           DA7219_HP_R_AMP_MIN_GAIN_EN_MASK);
+
        /* Default infinite tone gen, start/stop by Kcontrol */
        snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK);
 
index 66d3bad8673928d2e1e988a808f3431584056900..6baba7455fa12a2759f8e103d75fa834d0eb0fd2 100644 (file)
 #define DA7219_SYS_STAT_CHECK_RETRIES  6
 #define DA7219_SYS_STAT_CHECK_DELAY    50
 
+/* Power up/down Delays */
+#define DA7219_SETTLING_DELAY  40
+#define DA7219_MIN_GAIN_DELAY  30
+
 enum da7219_clk_src {
        DA7219_CLKSRC_MCLK = 0,
        DA7219_CLKSRC_MCLK_SQR,
@@ -814,6 +818,7 @@ struct da7219_priv {
 
        bool master;
        bool alc_en;
+       u8 gain_ramp_ctrl;
 };
 
 #endif /* __DA7219_H */
index 1a736e72a929999d3117a154cf8bc99188f2332e..8930322d712b7a60def8148c3cceab7a17a03f22 100644 (file)
@@ -278,43 +278,6 @@ int es8328_probe(struct device *dev, struct regmap *regmap);
 
 #define ES8328_REG_MAX         0x35
 
-#define ES8328_PLL1            0
-#define ES8328_PLL2            1
-
-/* clock inputs */
-#define ES8328_MCLK            0
-#define ES8328_PCMCLK          1
-
-/* clock divider id's */
-#define ES8328_PCMDIV          0
-#define ES8328_BCLKDIV         1
-#define ES8328_VXCLKDIV                2
-
-/* PCM clock dividers */
-#define ES8328_PCM_DIV_1       (0 << 6)
-#define ES8328_PCM_DIV_3       (2 << 6)
-#define ES8328_PCM_DIV_5_5     (3 << 6)
-#define ES8328_PCM_DIV_2       (4 << 6)
-#define ES8328_PCM_DIV_4       (5 << 6)
-#define ES8328_PCM_DIV_6       (6 << 6)
-#define ES8328_PCM_DIV_8       (7 << 6)
-
-/* BCLK clock dividers */
-#define ES8328_BCLK_DIV_1      (0 << 7)
-#define ES8328_BCLK_DIV_2      (1 << 7)
-#define ES8328_BCLK_DIV_4      (2 << 7)
-#define ES8328_BCLK_DIV_8      (3 << 7)
-
-/* VXCLK clock dividers */
-#define ES8328_VXCLK_DIV_1     (0 << 6)
-#define ES8328_VXCLK_DIV_2     (1 << 6)
-#define ES8328_VXCLK_DIV_4     (2 << 6)
-#define ES8328_VXCLK_DIV_8     (3 << 6)
-#define ES8328_VXCLK_DIV_16    (4 << 6)
-
-#define ES8328_DAI_HIFI                0
-#define ES8328_DAI_VOICE       1
-
 #define ES8328_1536FS          1536
 #define ES8328_1024FS          1024
 #define ES8328_768FS           768
index b904492d774473a99d5e1aa451f18ff276f83732..90b5948e0ff363a91538a28513e35e32e35a0ee1 100644 (file)
@@ -364,7 +364,12 @@ static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
                                  struct of_phandle_args *args,
                                  const char **dai_name)
 {
-       int id = args->args[0];
+       int id;
+
+       if (args->args_count)
+               id = args->args[0];
+       else
+               id = 0;
 
        if (id < ARRAY_SIZE(hdmi_dai_name)) {
                *dai_name = hdmi_dai_name[id];
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
new file mode 100644 (file)
index 0000000..d8e8590
--- /dev/null
@@ -0,0 +1,890 @@
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#define CDC_D_REVISION1                        (0xf000)
+#define CDC_D_PERPH_SUBTYPE            (0xf005)
+#define CDC_D_CDC_RST_CTL              (0xf046)
+#define RST_CTL_DIG_SW_RST_N_MASK      BIT(7)
+#define RST_CTL_DIG_SW_RST_N_RESET     0
+#define RST_CTL_DIG_SW_RST_N_REMOVE_RESET BIT(7)
+
+#define CDC_D_CDC_TOP_CLK_CTL          (0xf048)
+#define TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK (BIT(2) | BIT(3))
+#define TOP_CLK_CTL_A_MCLK_EN_ENABLE    BIT(2)
+#define TOP_CLK_CTL_A_MCLK2_EN_ENABLE  BIT(3)
+
+#define CDC_D_CDC_ANA_CLK_CTL          (0xf049)
+#define ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK BIT(0)
+#define ANA_CLK_CTL_EAR_HPHR_CLK_EN    BIT(0)
+#define ANA_CLK_CTL_EAR_HPHL_CLK_EN    BIT(1)
+#define ANA_CLK_CTL_SPKR_CLK_EN_MASK   BIT(4)
+#define ANA_CLK_CTL_SPKR_CLK_EN        BIT(4)
+#define ANA_CLK_CTL_TXA_CLK25_EN       BIT(5)
+
+#define CDC_D_CDC_DIG_CLK_CTL          (0xf04A)
+#define DIG_CLK_CTL_RXD1_CLK_EN                BIT(0)
+#define DIG_CLK_CTL_RXD2_CLK_EN                BIT(1)
+#define DIG_CLK_CTL_RXD3_CLK_EN                BIT(3)
+#define DIG_CLK_CTL_TXD_CLK_EN         BIT(4)
+#define DIG_CLK_CTL_NCP_CLK_EN_MASK    BIT(6)
+#define DIG_CLK_CTL_NCP_CLK_EN         BIT(6)
+#define DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK        BIT(7)
+#define DIG_CLK_CTL_RXD_PDM_CLK_EN     BIT(7)
+
+#define CDC_D_CDC_CONN_TX1_CTL         (0xf050)
+#define CONN_TX1_SERIAL_TX1_MUX                GENMASK(1, 0)
+#define CONN_TX1_SERIAL_TX1_ADC_1      0x0
+#define CONN_TX1_SERIAL_TX1_RX_PDM_LB  0x1
+#define CONN_TX1_SERIAL_TX1_ZERO       0x2
+
+#define CDC_D_CDC_CONN_TX2_CTL         (0xf051)
+#define CONN_TX2_SERIAL_TX2_MUX                GENMASK(1, 0)
+#define CONN_TX2_SERIAL_TX2_ADC_2      0x0
+#define CONN_TX2_SERIAL_TX2_RX_PDM_LB  0x1
+#define CONN_TX2_SERIAL_TX2_ZERO       0x2
+#define CDC_D_CDC_CONN_HPHR_DAC_CTL    (0xf052)
+#define CDC_D_CDC_CONN_RX1_CTL         (0xf053)
+#define CDC_D_CDC_CONN_RX2_CTL         (0xf054)
+#define CDC_D_CDC_CONN_RX3_CTL         (0xf055)
+#define CDC_D_CDC_CONN_RX_LB_CTL       (0xf056)
+#define CDC_D_SEC_ACCESS               (0xf0D0)
+#define CDC_D_PERPH_RESET_CTL3         (0xf0DA)
+#define CDC_D_PERPH_RESET_CTL4         (0xf0DB)
+#define CDC_A_REVISION1                        (0xf100)
+#define CDC_A_REVISION2                        (0xf101)
+#define CDC_A_REVISION3                        (0xf102)
+#define CDC_A_REVISION4                        (0xf103)
+#define CDC_A_PERPH_TYPE               (0xf104)
+#define CDC_A_PERPH_SUBTYPE            (0xf105)
+#define CDC_A_INT_RT_STS               (0xf110)
+#define CDC_A_INT_SET_TYPE             (0xf111)
+#define CDC_A_INT_POLARITY_HIGH                (0xf112)
+#define CDC_A_INT_POLARITY_LOW         (0xf113)
+#define CDC_A_INT_LATCHED_CLR          (0xf114)
+#define CDC_A_INT_EN_SET               (0xf115)
+#define CDC_A_INT_EN_CLR               (0xf116)
+#define CDC_A_INT_LATCHED_STS          (0xf118)
+#define CDC_A_INT_PENDING_STS          (0xf119)
+#define CDC_A_INT_MID_SEL              (0xf11A)
+#define CDC_A_INT_PRIORITY             (0xf11B)
+#define CDC_A_MICB_1_EN                        (0xf140)
+#define MICB_1_EN_MICB_ENABLE          BIT(7)
+#define MICB_1_EN_BYP_CAP_MASK         BIT(6)
+#define MICB_1_EN_NO_EXT_BYP_CAP       BIT(6)
+#define MICB_1_EN_EXT_BYP_CAP          0
+#define MICB_1_EN_PULL_DOWN_EN_MASK    BIT(5)
+#define MICB_1_EN_PULL_DOWN_EN_ENABLE  BIT(5)
+#define MICB_1_EN_OPA_STG2_TAIL_CURR_MASK GENMASK(3, 1)
+#define MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA    (0x4)
+#define MICB_1_EN_PULL_UP_EN_MASK      BIT(4)
+#define MICB_1_EN_TX3_GND_SEL_MASK     BIT(0)
+#define MICB_1_EN_TX3_GND_SEL_TX_GND   0
+
+#define CDC_A_MICB_1_VAL               (0xf141)
+#define MICB_1_VAL_MICB_OUT_VAL_MASK   GENMASK(7, 3)
+#define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16)  << 3)
+#define CDC_A_MICB_1_CTL               (0xf142)
+
+#define MICB_1_CTL_CFILT_REF_SEL_MASK          BIT(1)
+#define MICB_1_CTL_CFILT_REF_SEL_HPF_REF       BIT(1)
+#define MICB_1_CTL_EXT_PRECHARG_EN_MASK                BIT(5)
+#define MICB_1_CTL_EXT_PRECHARG_EN_ENABLE      BIT(5)
+#define MICB_1_CTL_INT_PRECHARG_BYP_MASK       BIT(6)
+#define MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL    BIT(6)
+
+#define CDC_A_MICB_1_INT_RBIAS                 (0xf143)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_MASK       BIT(7)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE     BIT(7)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_DISABLE    0
+
+#define MICB_1_INT_TX1_INT_PULLUP_EN_MASK      BIT(6)
+#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(6)
+#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_GND       0
+
+#define MICB_1_INT_TX2_INT_RBIAS_EN_MASK       BIT(4)
+#define MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE     BIT(4)
+#define MICB_1_INT_TX2_INT_RBIAS_EN_DISABLE    0
+#define MICB_1_INT_TX2_INT_PULLUP_EN_MASK      BIT(3)
+#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(3)
+#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_GND       0
+
+#define MICB_1_INT_TX3_INT_RBIAS_EN_MASK       BIT(1)
+#define MICB_1_INT_TX3_INT_RBIAS_EN_ENABLE     BIT(1)
+#define MICB_1_INT_TX3_INT_RBIAS_EN_DISABLE    0
+#define MICB_1_INT_TX3_INT_PULLUP_EN_MASK      BIT(0)
+#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(0)
+#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND       0
+
+#define CDC_A_MICB_2_EN                        (0xf144)
+#define CDC_A_TX_1_2_ATEST_CTL_2       (0xf145)
+#define CDC_A_MASTER_BIAS_CTL          (0xf146)
+#define CDC_A_TX_1_EN                  (0xf160)
+#define CDC_A_TX_2_EN                  (0xf161)
+#define CDC_A_TX_1_2_TEST_CTL_1                (0xf162)
+#define CDC_A_TX_1_2_TEST_CTL_2                (0xf163)
+#define CDC_A_TX_1_2_ATEST_CTL         (0xf164)
+#define CDC_A_TX_1_2_OPAMP_BIAS                (0xf165)
+#define CDC_A_TX_3_EN                  (0xf167)
+#define CDC_A_NCP_EN                   (0xf180)
+#define CDC_A_NCP_CLK                  (0xf181)
+#define CDC_A_NCP_FBCTRL               (0xf183)
+#define CDC_A_NCP_FBCTRL_FB_CLK_INV_MASK       BIT(5)
+#define CDC_A_NCP_FBCTRL_FB_CLK_INV            BIT(5)
+#define CDC_A_NCP_BIAS                 (0xf184)
+#define CDC_A_NCP_VCTRL                        (0xf185)
+#define CDC_A_NCP_TEST                 (0xf186)
+#define CDC_A_NCP_CLIM_ADDR            (0xf187)
+#define CDC_A_RX_CLOCK_DIVIDER         (0xf190)
+#define CDC_A_RX_COM_OCP_CTL           (0xf191)
+#define CDC_A_RX_COM_OCP_COUNT         (0xf192)
+#define CDC_A_RX_COM_BIAS_DAC          (0xf193)
+#define RX_COM_BIAS_DAC_RX_BIAS_EN_MASK                BIT(7)
+#define RX_COM_BIAS_DAC_RX_BIAS_EN_ENABLE      BIT(7)
+#define RX_COM_BIAS_DAC_DAC_REF_EN_MASK                BIT(0)
+#define RX_COM_BIAS_DAC_DAC_REF_EN_ENABLE      BIT(0)
+
+#define CDC_A_RX_HPH_BIAS_PA           (0xf194)
+#define CDC_A_RX_HPH_BIAS_LDO_OCP      (0xf195)
+#define CDC_A_RX_HPH_BIAS_CNP          (0xf196)
+#define CDC_A_RX_HPH_CNP_EN            (0xf197)
+#define CDC_A_RX_HPH_L_PA_DAC_CTL      (0xf19B)
+#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK    BIT(1)
+#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET   BIT(1)
+#define CDC_A_RX_HPH_R_PA_DAC_CTL      (0xf19D)
+#define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1)
+#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1)
+
+#define CDC_A_RX_EAR_CTL                       (0xf19E)
+#define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK                BIT(0)
+#define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE      BIT(0)
+
+#define CDC_A_SPKR_DAC_CTL             (0xf1B0)
+#define SPKR_DAC_CTL_DAC_RESET_MASK    BIT(4)
+#define SPKR_DAC_CTL_DAC_RESET_NORMAL  0
+
+#define CDC_A_SPKR_DRV_CTL             (0xf1B2)
+#define SPKR_DRV_CTL_DEF_MASK          0xEF
+#define SPKR_DRV_CLASSD_PA_EN_MASK     BIT(7)
+#define SPKR_DRV_CLASSD_PA_EN_ENABLE   BIT(7)
+#define SPKR_DRV_CAL_EN                        BIT(6)
+#define SPKR_DRV_SETTLE_EN             BIT(5)
+#define SPKR_DRV_FW_EN                 BIT(3)
+#define SPKR_DRV_BOOST_SET             BIT(2)
+#define SPKR_DRV_CMFB_SET              BIT(1)
+#define SPKR_DRV_GAIN_SET              BIT(0)
+#define SPKR_DRV_CTL_DEF_VAL (SPKR_DRV_CLASSD_PA_EN_ENABLE | \
+               SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \
+               SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \
+               SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET)
+#define CDC_A_SPKR_OCP_CTL             (0xf1B4)
+#define CDC_A_SPKR_PWRSTG_CTL          (0xf1B5)
+#define SPKR_PWRSTG_CTL_DAC_EN_MASK    BIT(0)
+#define SPKR_PWRSTG_CTL_DAC_EN         BIT(0)
+#define SPKR_PWRSTG_CTL_MASK           0xE0
+#define SPKR_PWRSTG_CTL_BBM_MASK       BIT(7)
+#define SPKR_PWRSTG_CTL_BBM_EN         BIT(7)
+#define SPKR_PWRSTG_CTL_HBRDGE_EN_MASK BIT(6)
+#define SPKR_PWRSTG_CTL_HBRDGE_EN      BIT(6)
+#define SPKR_PWRSTG_CTL_CLAMP_EN_MASK  BIT(5)
+#define SPKR_PWRSTG_CTL_CLAMP_EN       BIT(5)
+
+#define CDC_A_SPKR_DRV_DBG             (0xf1B7)
+#define CDC_A_CURRENT_LIMIT            (0xf1C0)
+#define CDC_A_BOOST_EN_CTL             (0xf1C3)
+#define CDC_A_SLOPE_COMP_IP_ZERO       (0xf1C4)
+#define CDC_A_SEC_ACCESS               (0xf1D0)
+#define CDC_A_PERPH_RESET_CTL3         (0xf1DA)
+#define CDC_A_PERPH_RESET_CTL4         (0xf1DB)
+
+#define MSM8916_WCD_ANALOG_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                                   SNDRV_PCM_FMTBIT_S24_LE)
+
+static const char * const supply_names[] = {
+       "vdd-cdc-io",
+       "vdd-cdc-tx-rx-cx",
+};
+
+struct pm8916_wcd_analog_priv {
+       u16 pmic_rev;
+       u16 codec_version;
+       struct clk *mclk;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+       bool micbias1_cap_mode;
+       bool micbias2_cap_mode;
+};
+
+static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
+static const char *const rdac2_mux_text[] = { "ZERO", "RX2", "RX1" };
+static const char *const hph_text[] = { "ZERO", "Switch", };
+
+static const struct soc_enum hph_enum = SOC_ENUM_SINGLE_VIRT(
+                                       ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum);
+static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum);
+
+/* ADC2 MUX */
+static const struct soc_enum adc2_enum = SOC_ENUM_SINGLE_VIRT(
+                       ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+/* RDAC2 MUX */
+static const struct soc_enum rdac2_mux_enum = SOC_ENUM_SINGLE(
+                       CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 3, rdac2_mux_text);
+
+static const struct snd_kcontrol_new spkr_switch[] = {
+       SOC_DAPM_SINGLE("Switch", CDC_A_SPKR_DAC_CTL, 7, 1, 0)
+};
+
+static const struct snd_kcontrol_new rdac2_mux = SOC_DAPM_ENUM(
+                                       "RDAC2 MUX Mux", rdac2_mux_enum);
+static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM(
+                                       "ADC2 MUX Mux", adc2_enum);
+
+/* Analog Gain control 0 dB to +24 dB in 6 dB steps */
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 600, 0);
+
+static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = {
+       SOC_SINGLE_TLV("ADC1 Volume", CDC_A_TX_1_EN, 3, 8, 0, analog_gain),
+       SOC_SINGLE_TLV("ADC2 Volume", CDC_A_TX_2_EN, 3, 8, 0, analog_gain),
+       SOC_SINGLE_TLV("ADC3 Volume", CDC_A_TX_3_EN, 3, 8, 0, analog_gain),
+};
+
+static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec)
+{
+       snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                           MICB_1_CTL_EXT_PRECHARG_EN_MASK |
+                           MICB_1_CTL_INT_PRECHARG_BYP_MASK,
+                           MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
+                           | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
+
+       snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V);
+       /*
+        * Special headset needs MICBIAS as 2.7V so wait for
+        * 50 msec for the MICBIAS to reach 2.7 volts.
+        */
+       msleep(50);
+       snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                           MICB_1_CTL_EXT_PRECHARG_EN_MASK |
+                           MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
+
+}
+
+static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec
+                                                *codec, int event,
+                                                int reg, u32 cap_mode)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               pm8916_wcd_analog_micbias_enable(codec);
+               snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                   MICB_1_EN_BYP_CAP_MASK, cap_mode);
+               break;
+       }
+
+       return 0;
+}
+
+static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_codec
+                                                *codec, int event,
+                                                int reg, u32 cap_mode)
+{
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                   MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+                                   MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+               snd_soc_update_bits(codec, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0);
+               snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                   MICB_1_EN_OPA_STG2_TAIL_CURR_MASK,
+                                   MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA);
+
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               pm8916_wcd_analog_micbias_enable(codec);
+               snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                   MICB_1_EN_BYP_CAP_MASK, cap_mode);
+               break;
+       }
+
+       return 0;
+}
+
+static int pm8916_wcd_analog_enable_micbias_ext1(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 pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+       return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg,
+                                                    wcd->micbias1_cap_mode);
+}
+
+static int pm8916_wcd_analog_enable_micbias_ext2(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 pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+       return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg,
+                                                    wcd->micbias2_cap_mode);
+
+}
+
+static int pm8916_wcd_analog_enable_micbias_int1(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 pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+       return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
+                                                    wcd->micbias1_cap_mode);
+}
+
+static int pm8916_wcd_analog_enable_micbias_int2(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 pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+       return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg,
+                                                    wcd->micbias2_cap_mode);
+}
+
+static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w,
+                                        struct snd_kcontrol *kcontrol,
+                                        int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       u16 adc_reg = CDC_A_TX_1_2_TEST_CTL_2;
+       u8 init_bit_shift;
+
+       if (w->reg == CDC_A_TX_1_EN)
+               init_bit_shift = 5;
+       else
+               init_bit_shift = 4;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (w->reg == CDC_A_TX_2_EN)
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                                           MICB_1_CTL_CFILT_REF_SEL_MASK,
+                                           MICB_1_CTL_CFILT_REF_SEL_HPF_REF);
+               /*
+                * Add delay of 10 ms to give sufficient time for the voltage
+                * to shoot up and settle so that the txfe init does not
+                * happen when the input voltage is changing too much.
+                */
+               usleep_range(10000, 10010);
+               snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+                                   1 << init_bit_shift);
+               switch (w->reg) {
+               case CDC_A_TX_1_EN:
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL,
+                                           CONN_TX1_SERIAL_TX1_MUX,
+                                           CONN_TX1_SERIAL_TX1_ADC_1);
+                       break;
+               case CDC_A_TX_2_EN:
+               case CDC_A_TX_3_EN:
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
+                                           CONN_TX2_SERIAL_TX2_MUX,
+                                           CONN_TX2_SERIAL_TX2_ADC_2);
+                       break;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               /*
+                * Add delay of 12 ms before deasserting the init
+                * to reduce the tx pop
+                */
+               usleep_range(12000, 12010);
+               snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               switch (w->reg) {
+               case CDC_A_TX_1_EN:
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL,
+                                           CONN_TX1_SERIAL_TX1_MUX,
+                                           CONN_TX1_SERIAL_TX1_ZERO);
+                       break;
+               case CDC_A_TX_2_EN:
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                                           MICB_1_CTL_CFILT_REF_SEL_MASK, 0);
+               case CDC_A_TX_3_EN:
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
+                                           CONN_TX2_SERIAL_TX2_MUX,
+                                           CONN_TX2_SERIAL_TX2_ZERO);
+                       break;
+               }
+
+
+               break;
+       }
+       return 0;
+}
+
+static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w,
+                                           struct snd_kcontrol *kcontrol,
+                                           int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+                                   SPKR_PWRSTG_CTL_DAC_EN_MASK |
+                                   SPKR_PWRSTG_CTL_BBM_MASK |
+                                   SPKR_PWRSTG_CTL_HBRDGE_EN_MASK |
+                                   SPKR_PWRSTG_CTL_CLAMP_EN_MASK,
+                                   SPKR_PWRSTG_CTL_DAC_EN|
+                                   SPKR_PWRSTG_CTL_BBM_EN |
+                                   SPKR_PWRSTG_CTL_HBRDGE_EN |
+                                   SPKR_PWRSTG_CTL_CLAMP_EN);
+
+               snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL,
+                                   RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK,
+                                   RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, CDC_A_SPKR_DRV_CTL,
+                                   SPKR_DRV_CTL_DEF_MASK,
+                                   SPKR_DRV_CTL_DEF_VAL);
+               snd_soc_update_bits(codec, w->reg,
+                                   SPKR_DRV_CLASSD_PA_EN_MASK,
+                                   SPKR_DRV_CLASSD_PA_EN_ENABLE);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+                                   SPKR_PWRSTG_CTL_DAC_EN_MASK|
+                                   SPKR_PWRSTG_CTL_BBM_MASK |
+                                   SPKR_PWRSTG_CTL_HBRDGE_EN_MASK |
+                                   SPKR_PWRSTG_CTL_CLAMP_EN_MASK, 0);
+
+               snd_soc_update_bits(codec, CDC_A_SPKR_DAC_CTL,
+                                   SPKR_DAC_CTL_DAC_RESET_MASK,
+                                   SPKR_DAC_CTL_DAC_RESET_NORMAL);
+               snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL,
+                                   RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, 0);
+               break;
+       }
+       return 0;
+}
+
+static const struct reg_default wcd_reg_defaults_2_0[] = {
+       {CDC_A_RX_COM_OCP_CTL, 0xD1},
+       {CDC_A_RX_COM_OCP_COUNT, 0xFF},
+       {CDC_D_SEC_ACCESS, 0xA5},
+       {CDC_D_PERPH_RESET_CTL3, 0x0F},
+       {CDC_A_TX_1_2_OPAMP_BIAS, 0x4F},
+       {CDC_A_NCP_FBCTRL, 0x28},
+       {CDC_A_SPKR_DRV_CTL, 0x69},
+       {CDC_A_SPKR_DRV_DBG, 0x01},
+       {CDC_A_BOOST_EN_CTL, 0x5F},
+       {CDC_A_SLOPE_COMP_IP_ZERO, 0x88},
+       {CDC_A_SEC_ACCESS, 0xA5},
+       {CDC_A_PERPH_RESET_CTL3, 0x0F},
+       {CDC_A_CURRENT_LIMIT, 0x82},
+       {CDC_A_SPKR_DAC_CTL, 0x03},
+       {CDC_A_SPKR_OCP_CTL, 0xE1},
+       {CDC_A_MASTER_BIAS_CTL, 0x30},
+};
+
+static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec)
+{
+       struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
+       int err, reg;
+
+       err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
+       if (err != 0) {
+               dev_err(codec->dev, "failed to enable regulators (%d)\n", err);
+               return err;
+       }
+
+       snd_soc_codec_set_drvdata(codec, priv);
+       priv->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1);
+       priv->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE);
+
+       dev_info(codec->dev, "PMIC REV: %d\t CODEC Version: %d\n",
+                priv->pmic_rev, priv->codec_version);
+
+       snd_soc_write(codec, CDC_D_PERPH_RESET_CTL4, 0x01);
+       snd_soc_write(codec, CDC_A_PERPH_RESET_CTL4, 0x01);
+
+       for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++)
+               snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
+                             wcd_reg_defaults_2_0[reg].def);
+
+       return 0;
+}
+
+static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec)
+{
+       struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev);
+
+       return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
+                                     priv->supplies);
+}
+
+static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = {
+
+       {"PDM_RX1", NULL, "PDM Playback"},
+       {"PDM_RX2", NULL, "PDM Playback"},
+       {"PDM_RX3", NULL, "PDM Playback"},
+       {"PDM Capture", NULL, "PDM_TX"},
+
+       /* ADC Connections */
+       {"PDM_TX", NULL, "ADC2"},
+       {"PDM_TX", NULL, "ADC3"},
+       {"ADC2", NULL, "ADC2 MUX"},
+       {"ADC3", NULL, "ADC2 MUX"},
+       {"ADC2 MUX", "INP2", "ADC2_INP2"},
+       {"ADC2 MUX", "INP3", "ADC2_INP3"},
+
+       {"PDM_TX", NULL, "ADC1"},
+       {"ADC1", NULL, "AMIC1"},
+       {"ADC2_INP2", NULL, "AMIC2"},
+       {"ADC2_INP3", NULL, "AMIC3"},
+
+       /* RDAC Connections */
+       {"HPHR DAC", NULL, "RDAC2 MUX"},
+       {"RDAC2 MUX", "RX1", "PDM_RX1"},
+       {"RDAC2 MUX", "RX2", "PDM_RX2"},
+       {"HPHL DAC", NULL, "PDM_RX1"},
+       {"PDM_RX1", NULL, "RXD1_CLK"},
+       {"PDM_RX2", NULL, "RXD2_CLK"},
+       {"PDM_RX3", NULL, "RXD3_CLK"},
+
+       {"PDM_RX1", NULL, "RXD_PDM_CLK"},
+       {"PDM_RX2", NULL, "RXD_PDM_CLK"},
+       {"PDM_RX3", NULL, "RXD_PDM_CLK"},
+
+       {"ADC1", NULL, "TXD_CLK"},
+       {"ADC2", NULL, "TXD_CLK"},
+       {"ADC3", NULL, "TXD_CLK"},
+
+       {"ADC1", NULL, "TXA_CLK25"},
+       {"ADC2", NULL, "TXA_CLK25"},
+       {"ADC3", NULL, "TXA_CLK25"},
+
+       {"PDM_RX1", NULL, "A_MCLK2"},
+       {"PDM_RX2", NULL, "A_MCLK2"},
+       {"PDM_RX3", NULL, "A_MCLK2"},
+
+       {"PDM_TX", NULL, "A_MCLK2"},
+       {"A_MCLK2", NULL, "A_MCLK"},
+
+       /* Headset (RX MIX1 and RX MIX2) */
+       {"HEADPHONE", NULL, "HPHL PA"},
+       {"HEADPHONE", NULL, "HPHR PA"},
+
+       {"HPHL PA", NULL, "EAR_HPHL_CLK"},
+       {"HPHR PA", NULL, "EAR_HPHR_CLK"},
+
+       {"CP", NULL, "NCP_CLK"},
+
+       {"HPHL PA", NULL, "HPHL"},
+       {"HPHR PA", NULL, "HPHR"},
+       {"HPHL PA", NULL, "CP"},
+       {"HPHL PA", NULL, "RX_BIAS"},
+       {"HPHR PA", NULL, "CP"},
+       {"HPHR PA", NULL, "RX_BIAS"},
+       {"HPHL", "Switch", "HPHL DAC"},
+       {"HPHR", "Switch", "HPHR DAC"},
+
+       {"RX_BIAS", NULL, "DAC_REF"},
+
+       {"SPK_OUT", NULL, "SPK PA"},
+       {"SPK PA", NULL, "RX_BIAS"},
+       {"SPK PA", NULL, "SPKR_CLK"},
+       {"SPK PA", NULL, "SPK DAC"},
+       {"SPK DAC", "Switch", "PDM_RX3"},
+
+       {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
+       {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+       {"MIC BIAS External1", NULL, "INT_LDO_H"},
+       {"MIC BIAS External2", NULL, "INT_LDO_H"},
+       {"MIC BIAS Internal1", NULL, "vdd-micbias"},
+       {"MIC BIAS Internal2", NULL, "vdd-micbias"},
+       {"MIC BIAS External1", NULL, "vdd-micbias"},
+       {"MIC BIAS External2", NULL, "vdd-micbias"},
+};
+
+static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
+
+       SND_SOC_DAPM_AIF_IN("PDM_RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("PDM_RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("PDM_RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("PDM_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_INPUT("AMIC1"),
+       SND_SOC_DAPM_INPUT("AMIC3"),
+       SND_SOC_DAPM_INPUT("AMIC2"),
+       SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+
+       /* RX stuff */
+       SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux),
+       SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
+                          0),
+       SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux),
+       SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
+                          0),
+       SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
+                          spkr_switch, ARRAY_SIZE(spkr_switch)),
+
+       /* Speaker */
+       SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+       SND_SOC_DAPM_PGA_E("SPK PA", CDC_A_SPKR_DRV_CTL,
+                          6, 0, NULL, 0,
+                          pm8916_wcd_analog_enable_spk_pa,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micbias", 0, 0),
+       SND_SOC_DAPM_SUPPLY("CP", CDC_A_NCP_EN, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DAC_REF", CDC_A_RX_COM_BIAS_DAC, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RX_BIAS", CDC_A_RX_COM_BIAS_DAC, 7, 0, NULL, 0),
+
+       /* TX */
+       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal1", CDC_A_MICB_1_EN, 7, 0,
+                           pm8916_wcd_analog_enable_micbias_int1,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal2", CDC_A_MICB_2_EN, 7, 0,
+                           pm8916_wcd_analog_enable_micbias_int2,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0,
+                           pm8916_wcd_analog_enable_micbias_ext1,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0,
+                           pm8916_wcd_analog_enable_micbias_ext2,
+                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0,
+                          pm8916_wcd_analog_enable_adc,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, CDC_A_TX_2_EN, 7, 0,
+                          pm8916_wcd_analog_enable_adc,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, CDC_A_TX_3_EN, 7, 0,
+                          pm8916_wcd_analog_enable_adc,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+       SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
+
+       /* Analog path clocks */
+       SND_SOC_DAPM_SUPPLY("EAR_HPHR_CLK", CDC_D_CDC_ANA_CLK_CTL, 0, 0, NULL,
+                           0),
+       SND_SOC_DAPM_SUPPLY("EAR_HPHL_CLK", CDC_D_CDC_ANA_CLK_CTL, 1, 0, NULL,
+                           0),
+       SND_SOC_DAPM_SUPPLY("SPKR_CLK", CDC_D_CDC_ANA_CLK_CTL, 4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("TXA_CLK25", CDC_D_CDC_ANA_CLK_CTL, 5, 0, NULL, 0),
+
+       /* Digital path clocks */
+
+       SND_SOC_DAPM_SUPPLY("RXD1_CLK", CDC_D_CDC_DIG_CLK_CTL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RXD2_CLK", CDC_D_CDC_DIG_CLK_CTL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RXD3_CLK", CDC_D_CDC_DIG_CLK_CTL, 2, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("TXD_CLK", CDC_D_CDC_DIG_CLK_CTL, 4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("NCP_CLK", CDC_D_CDC_DIG_CLK_CTL, 6, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RXD_PDM_CLK", CDC_D_CDC_DIG_CLK_CTL, 7, 0, NULL,
+                           0),
+
+       /* System Clock source */
+       SND_SOC_DAPM_SUPPLY("A_MCLK", CDC_D_CDC_TOP_CLK_CTL, 2, 0, NULL, 0),
+       /* TX ADC and RX DAC Clock source. */
+       SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0),
+};
+
+static struct regmap *pm8916_get_regmap(struct device *dev)
+{
+       return dev_get_regmap(dev->parent, NULL);
+}
+
+static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream,
+                                     struct snd_soc_dai *dai)
+{
+       snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
+                           RST_CTL_DIG_SW_RST_N_MASK,
+                           RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+
+       return 0;
+}
+
+static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream,
+                                        struct snd_soc_dai *dai)
+{
+       snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL,
+                           RST_CTL_DIG_SW_RST_N_MASK, 0);
+}
+
+static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = {
+       .startup = pm8916_wcd_analog_startup,
+       .shutdown = pm8916_wcd_analog_shutdown,
+};
+
+static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = {
+       [0] = {
+              .name = "pm8916_wcd_analog_pdm_rx",
+              .id = 0,
+              .playback = {
+                           .stream_name = "PDM Playback",
+                           .rates = MSM8916_WCD_ANALOG_RATES,
+                           .formats = MSM8916_WCD_ANALOG_FORMATS,
+                           .channels_min = 1,
+                           .channels_max = 3,
+                           },
+              .ops = &pm8916_wcd_analog_dai_ops,
+              },
+       [1] = {
+              .name = "pm8916_wcd_analog_pdm_tx",
+              .id = 1,
+              .capture = {
+                          .stream_name = "PDM Capture",
+                          .rates = MSM8916_WCD_ANALOG_RATES,
+                          .formats = MSM8916_WCD_ANALOG_FORMATS,
+                          .channels_min = 1,
+                          .channels_max = 4,
+                          },
+              .ops = &pm8916_wcd_analog_dai_ops,
+              },
+};
+
+static struct snd_soc_codec_driver pm8916_wcd_analog = {
+       .probe = pm8916_wcd_analog_probe,
+       .remove = pm8916_wcd_analog_remove,
+       .get_regmap = pm8916_get_regmap,
+       .component_driver = {
+               .controls = pm8916_wcd_analog_snd_controls,
+               .num_controls = ARRAY_SIZE(pm8916_wcd_analog_snd_controls),
+               .dapm_widgets = pm8916_wcd_analog_dapm_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(pm8916_wcd_analog_dapm_widgets),
+               .dapm_routes = pm8916_wcd_analog_audio_map,
+               .num_dapm_routes = ARRAY_SIZE(pm8916_wcd_analog_audio_map),
+       },
+};
+
+static int pm8916_wcd_analog_parse_dt(struct device *dev,
+                                      struct pm8916_wcd_analog_priv *priv)
+{
+
+       if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap"))
+               priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
+       else
+               priv->micbias1_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+
+       if (of_property_read_bool(dev->of_node, "qcom,micbias2-ext-cap"))
+               priv->micbias2_cap_mode = MICB_1_EN_EXT_BYP_CAP;
+       else
+               priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+
+       return 0;
+}
+
+static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
+{
+       struct pm8916_wcd_analog_priv *priv;
+       struct device *dev = &pdev->dev;
+       int ret, i;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ret = pm8916_wcd_analog_parse_dt(dev, priv);
+       if (ret < 0)
+               return ret;
+
+       priv->mclk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(priv->mclk)) {
+               dev_err(dev, "failed to get mclk\n");
+               return PTR_ERR(priv->mclk);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               priv->supplies[i].supply = supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
+                                   priv->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to get regulator supplies %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(priv->mclk);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable mclk %d\n", ret);
+               return ret;
+       }
+
+       dev_set_drvdata(dev, priv);
+
+       return snd_soc_register_codec(dev, &pm8916_wcd_analog,
+                                     pm8916_wcd_analog_dai,
+                                     ARRAY_SIZE(pm8916_wcd_analog_dai));
+}
+
+static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev)
+{
+       struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_codec(&pdev->dev);
+       clk_disable_unprepare(priv->mclk);
+
+       return 0;
+}
+
+static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
+       { .compatible = "qcom,pm8916-wcd-analog-codec", },
+       { }
+};
+
+static struct platform_driver pm8916_wcd_analog_spmi_driver = {
+       .driver = {
+                  .name = "qcom,pm8916-wcd-spmi-codec",
+                  .of_match_table = pm8916_wcd_analog_spmi_match_table,
+       },
+       .probe = pm8916_wcd_analog_spmi_probe,
+       .remove = pm8916_wcd_analog_spmi_remove,
+};
+
+module_platform_driver(pm8916_wcd_analog_spmi_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("PMIC PM8916 WCD Analog Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c
new file mode 100644 (file)
index 0000000..f690442
--- /dev/null
@@ -0,0 +1,923 @@
+/* Copyright (c) 2016, 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/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#define LPASS_CDC_CLK_RX_RESET_CTL             (0x000)
+#define LPASS_CDC_CLK_TX_RESET_B1_CTL          (0x004)
+#define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK     BIT(0)
+#define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK     BIT(1)
+#define LPASS_CDC_CLK_DMIC_B1_CTL              (0x008)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK         GENMASK(3, 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2         (0x0 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3         (0x1 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4         (0x2 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6         (0x3 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16                (0x4 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_EN_MASK          BIT(0)
+#define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE                BIT(0)
+
+#define LPASS_CDC_CLK_RX_I2S_CTL               (0x00C)
+#define RX_I2S_CTL_RX_I2S_MODE_MASK            BIT(5)
+#define RX_I2S_CTL_RX_I2S_MODE_16              BIT(5)
+#define RX_I2S_CTL_RX_I2S_MODE_32              0
+#define RX_I2S_CTL_RX_I2S_FS_RATE_MASK         GENMASK(2, 0)
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ      0x0
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ     0x1
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ     0x2
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ     0x3
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ     0x4
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ    0x5
+#define LPASS_CDC_CLK_TX_I2S_CTL               (0x010)
+#define TX_I2S_CTL_TX_I2S_MODE_MASK            BIT(5)
+#define TX_I2S_CTL_TX_I2S_MODE_16              BIT(5)
+#define TX_I2S_CTL_TX_I2S_MODE_32              0
+#define TX_I2S_CTL_TX_I2S_FS_RATE_MASK         GENMASK(2, 0)
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ      0x0
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ     0x1
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ     0x2
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ     0x3
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ     0x4
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ    0x5
+
+#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL                (0x014)
+#define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL         (0x018)
+#define LPASS_CDC_CLK_OTHR_CTL                 (0x01C)
+#define LPASS_CDC_CLK_RX_B1_CTL                        (0x020)
+#define LPASS_CDC_CLK_MCLK_CTL                 (0x024)
+#define MCLK_CTL_MCLK_EN_MASK                  BIT(0)
+#define MCLK_CTL_MCLK_EN_ENABLE                        BIT(0)
+#define MCLK_CTL_MCLK_EN_DISABLE               0
+#define LPASS_CDC_CLK_PDM_CTL                  (0x028)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK      BIT(0)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_EN           BIT(0)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK BIT(1)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB   BIT(1)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK  0
+
+#define LPASS_CDC_CLK_SD_CTL                   (0x02C)
+#define LPASS_CDC_RX1_B1_CTL                   (0x040)
+#define LPASS_CDC_RX2_B1_CTL                   (0x060)
+#define LPASS_CDC_RX3_B1_CTL                   (0x080)
+#define LPASS_CDC_RX1_B2_CTL                   (0x044)
+#define LPASS_CDC_RX2_B2_CTL                   (0x064)
+#define LPASS_CDC_RX3_B2_CTL                   (0x084)
+#define LPASS_CDC_RX1_B3_CTL                   (0x048)
+#define LPASS_CDC_RX2_B3_CTL                   (0x068)
+#define LPASS_CDC_RX3_B3_CTL                   (0x088)
+#define LPASS_CDC_RX1_B4_CTL                   (0x04C)
+#define LPASS_CDC_RX2_B4_CTL                   (0x06C)
+#define LPASS_CDC_RX3_B4_CTL                   (0x08C)
+#define LPASS_CDC_RX1_B5_CTL                   (0x050)
+#define LPASS_CDC_RX2_B5_CTL                   (0x070)
+#define LPASS_CDC_RX3_B5_CTL                   (0x090)
+#define LPASS_CDC_RX1_B6_CTL                   (0x054)
+#define RXn_B6_CTL_MUTE_MASK                   BIT(0)
+#define RXn_B6_CTL_MUTE_ENABLE                 BIT(0)
+#define RXn_B6_CTL_MUTE_DISABLE                        0
+#define LPASS_CDC_RX2_B6_CTL                   (0x074)
+#define LPASS_CDC_RX3_B6_CTL                   (0x094)
+#define LPASS_CDC_RX1_VOL_CTL_B1_CTL           (0x058)
+#define LPASS_CDC_RX2_VOL_CTL_B1_CTL           (0x078)
+#define LPASS_CDC_RX3_VOL_CTL_B1_CTL           (0x098)
+#define LPASS_CDC_RX1_VOL_CTL_B2_CTL           (0x05C)
+#define LPASS_CDC_RX2_VOL_CTL_B2_CTL           (0x07C)
+#define LPASS_CDC_RX3_VOL_CTL_B2_CTL           (0x09C)
+#define LPASS_CDC_TOP_GAIN_UPDATE              (0x0A0)
+#define LPASS_CDC_TOP_CTL                      (0x0A4)
+#define TOP_CTL_DIG_MCLK_FREQ_MASK             BIT(0)
+#define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ      0
+#define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ         BIT(0)
+
+#define LPASS_CDC_DEBUG_DESER1_CTL             (0x0E0)
+#define LPASS_CDC_DEBUG_DESER2_CTL             (0x0E4)
+#define LPASS_CDC_DEBUG_B1_CTL_CFG             (0x0E8)
+#define LPASS_CDC_DEBUG_B2_CTL_CFG             (0x0EC)
+#define LPASS_CDC_DEBUG_B3_CTL_CFG             (0x0F0)
+#define LPASS_CDC_IIR1_GAIN_B1_CTL             (0x100)
+#define LPASS_CDC_IIR2_GAIN_B1_CTL             (0x140)
+#define LPASS_CDC_IIR1_GAIN_B2_CTL             (0x104)
+#define LPASS_CDC_IIR2_GAIN_B2_CTL             (0x144)
+#define LPASS_CDC_IIR1_GAIN_B3_CTL             (0x108)
+#define LPASS_CDC_IIR2_GAIN_B3_CTL             (0x148)
+#define LPASS_CDC_IIR1_GAIN_B4_CTL             (0x10C)
+#define LPASS_CDC_IIR2_GAIN_B4_CTL             (0x14C)
+#define LPASS_CDC_IIR1_GAIN_B5_CTL             (0x110)
+#define LPASS_CDC_IIR2_GAIN_B5_CTL             (0x150)
+#define LPASS_CDC_IIR1_GAIN_B6_CTL             (0x114)
+#define LPASS_CDC_IIR2_GAIN_B6_CTL             (0x154)
+#define LPASS_CDC_IIR1_GAIN_B7_CTL             (0x118)
+#define LPASS_CDC_IIR2_GAIN_B7_CTL             (0x158)
+#define LPASS_CDC_IIR1_GAIN_B8_CTL             (0x11C)
+#define LPASS_CDC_IIR2_GAIN_B8_CTL             (0x15C)
+#define LPASS_CDC_IIR1_CTL                     (0x120)
+#define LPASS_CDC_IIR2_CTL                     (0x160)
+#define LPASS_CDC_IIR1_GAIN_TIMER_CTL          (0x124)
+#define LPASS_CDC_IIR2_GAIN_TIMER_CTL          (0x164)
+#define LPASS_CDC_IIR1_COEF_B1_CTL             (0x128)
+#define LPASS_CDC_IIR2_COEF_B1_CTL             (0x168)
+#define LPASS_CDC_IIR1_COEF_B2_CTL             (0x12C)
+#define LPASS_CDC_IIR2_COEF_B2_CTL             (0x16C)
+#define LPASS_CDC_CONN_RX1_B1_CTL              (0x180)
+#define LPASS_CDC_CONN_RX1_B2_CTL              (0x184)
+#define LPASS_CDC_CONN_RX1_B3_CTL              (0x188)
+#define LPASS_CDC_CONN_RX2_B1_CTL              (0x18C)
+#define LPASS_CDC_CONN_RX2_B2_CTL              (0x190)
+#define LPASS_CDC_CONN_RX2_B3_CTL              (0x194)
+#define LPASS_CDC_CONN_RX3_B1_CTL              (0x198)
+#define LPASS_CDC_CONN_RX3_B2_CTL              (0x19C)
+#define LPASS_CDC_CONN_TX_B1_CTL               (0x1A0)
+#define LPASS_CDC_CONN_EQ1_B1_CTL              (0x1A8)
+#define LPASS_CDC_CONN_EQ1_B2_CTL              (0x1AC)
+#define LPASS_CDC_CONN_EQ1_B3_CTL              (0x1B0)
+#define LPASS_CDC_CONN_EQ1_B4_CTL              (0x1B4)
+#define LPASS_CDC_CONN_EQ2_B1_CTL              (0x1B8)
+#define LPASS_CDC_CONN_EQ2_B2_CTL              (0x1BC)
+#define LPASS_CDC_CONN_EQ2_B3_CTL              (0x1C0)
+#define LPASS_CDC_CONN_EQ2_B4_CTL              (0x1C4)
+#define LPASS_CDC_CONN_TX_I2S_SD1_CTL          (0x1C8)
+#define LPASS_CDC_TX1_VOL_CTL_TIMER            (0x280)
+#define LPASS_CDC_TX2_VOL_CTL_TIMER            (0x2A0)
+#define LPASS_CDC_TX1_VOL_CTL_GAIN             (0x284)
+#define LPASS_CDC_TX2_VOL_CTL_GAIN             (0x2A4)
+#define LPASS_CDC_TX1_VOL_CTL_CFG              (0x288)
+#define TX_VOL_CTL_CFG_MUTE_EN_MASK            BIT(0)
+#define TX_VOL_CTL_CFG_MUTE_EN_ENABLE          BIT(0)
+
+#define LPASS_CDC_TX2_VOL_CTL_CFG              (0x2A8)
+#define LPASS_CDC_TX1_MUX_CTL                  (0x28C)
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK           GENMASK(5, 4)
+#define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT          4
+#define TX_MUX_CTL_CF_NEG_3DB_4HZ              (0x0 << 4)
+#define TX_MUX_CTL_CF_NEG_3DB_75HZ             (0x1 << 4)
+#define TX_MUX_CTL_CF_NEG_3DB_150HZ            (0x2 << 4)
+#define TX_MUX_CTL_HPF_BP_SEL_MASK             BIT(3)
+#define TX_MUX_CTL_HPF_BP_SEL_BYPASS           BIT(3)
+#define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS                0
+
+#define LPASS_CDC_TX2_MUX_CTL                  (0x2AC)
+#define LPASS_CDC_TX1_CLK_FS_CTL               (0x290)
+#define LPASS_CDC_TX2_CLK_FS_CTL               (0x2B0)
+#define LPASS_CDC_TX1_DMIC_CTL                 (0x294)
+#define LPASS_CDC_TX2_DMIC_CTL                 (0x2B4)
+#define TXN_DMIC_CTL_CLK_SEL_MASK              GENMASK(2, 0)
+#define TXN_DMIC_CTL_CLK_SEL_DIV2              0x0
+#define TXN_DMIC_CTL_CLK_SEL_DIV3              0x1
+#define TXN_DMIC_CTL_CLK_SEL_DIV4              0x2
+#define TXN_DMIC_CTL_CLK_SEL_DIV6              0x3
+#define TXN_DMIC_CTL_CLK_SEL_DIV16             0x4
+
+#define MSM8916_WCD_DIGITAL_RATES (SNDRV_PCM_RATE_8000 | \
+                                  SNDRV_PCM_RATE_16000 | \
+                                  SNDRV_PCM_RATE_32000 | \
+                                  SNDRV_PCM_RATE_48000)
+#define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                                    SNDRV_PCM_FMTBIT_S24_LE)
+
+struct msm8916_wcd_digital_priv {
+       struct clk *ahbclk, *mclk;
+};
+
+static const unsigned long rx_gain_reg[] = {
+       LPASS_CDC_RX1_VOL_CTL_B2_CTL,
+       LPASS_CDC_RX2_VOL_CTL_B2_CTL,
+       LPASS_CDC_RX3_VOL_CTL_B2_CTL,
+};
+
+static const unsigned long tx_gain_reg[] = {
+       LPASS_CDC_TX1_VOL_CTL_GAIN,
+       LPASS_CDC_TX2_VOL_CTL_GAIN,
+};
+
+static const char *const rx_mix1_text[] = {
+       "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
+};
+
+static const char *const dec_mux_text[] = {
+       "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
+};
+static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" };
+static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
+
+/* RX1 MIX1 */
+static const struct soc_enum rx_mix1_inp_enum[] = {
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text),
+};
+
+/* RX1 MIX2 */
+static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
+                               LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
+
+/* RX2 MIX1 */
+static const struct soc_enum rx2_mix1_inp_enum[] = {
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
+};
+
+/* RX2 MIX2 */
+static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE(
+                               LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
+
+/* RX3 MIX1 */
+static const struct soc_enum rx3_mix1_inp_enum[] = {
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
+};
+
+/* DEC */
+static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE(
+                               LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text);
+static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE(
+                               LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text);
+
+/* RDAC2 MUX */
+static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM(
+                               "DEC1 MUX Mux", dec1_mux_enum);
+static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM(
+                               "DEC2 MUX Mux", dec2_mux_enum);
+static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM(
+                               "RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]);
+static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM(
+                               "RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]);
+static const struct snd_kcontrol_new rx_mix1_inp3_mux = SOC_DAPM_ENUM(
+                               "RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]);
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux = SOC_DAPM_ENUM(
+                               "RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]);
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux = SOC_DAPM_ENUM(
+                               "RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]);
+static const struct snd_kcontrol_new rx2_mix1_inp3_mux = SOC_DAPM_ENUM(
+                               "RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]);
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux = SOC_DAPM_ENUM(
+                               "RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]);
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM(
+                               "RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]);
+static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM(
+                               "RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]);
+
+/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */
+static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0);
+
+/* Cutoff Freq for High Pass Filter at -3dB */
+static const char * const hpf_cutoff_text[] = {
+       "4Hz", "75Hz", "150Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(tx1_hpf_cutoff_enum, LPASS_CDC_TX1_MUX_CTL, 4,
+                           hpf_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(tx2_hpf_cutoff_enum, LPASS_CDC_TX2_MUX_CTL, 4,
+                           hpf_cutoff_text);
+
+/* cut off for dc blocker inside rx chain */
+static const char * const dc_blocker_cutoff_text[] = {
+       "4Hz", "75Hz", "150Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(rx1_dcb_cutoff_enum, LPASS_CDC_RX1_B4_CTL, 0,
+                           dc_blocker_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0,
+                           dc_blocker_cutoff_text);
+static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum, LPASS_CDC_RX3_B4_CTL, 0,
+                           dc_blocker_cutoff_text);
+
+static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = {
+       SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL,
+                         -128, 127, digital_gain),
+       SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL,
+                         -128, 127, digital_gain),
+       SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL,
+                         -128, 127, digital_gain),
+       SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN,
+                         -128, 127, digital_gain),
+       SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN,
+                         -128, 127, digital_gain),
+       SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum),
+       SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum),
+       SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0),
+       SOC_SINGLE("TX2 HPF Switch", LPASS_CDC_TX2_MUX_CTL, 3, 1, 0),
+       SOC_ENUM("RX1 DCB Cutoff", rx1_dcb_cutoff_enum),
+       SOC_ENUM("RX2 DCB Cutoff", rx2_dcb_cutoff_enum),
+       SOC_ENUM("RX3 DCB Cutoff", rx3_dcb_cutoff_enum),
+       SOC_SINGLE("RX1 DCB Switch", LPASS_CDC_RX1_B5_CTL, 2, 1, 0),
+       SOC_SINGLE("RX2 DCB Switch", LPASS_CDC_RX2_B5_CTL, 2, 1, 0),
+       SOC_SINGLE("RX3 DCB Switch", LPASS_CDC_RX3_B5_CTL, 2, 1, 0),
+       SOC_SINGLE("RX1 Mute Switch", LPASS_CDC_RX1_B6_CTL, 0, 1, 0),
+       SOC_SINGLE("RX2 Mute Switch", LPASS_CDC_RX2_B6_CTL, 0, 1, 0),
+       SOC_SINGLE("RX3 Mute Switch", LPASS_CDC_RX3_B6_CTL, 0, 1, 0),
+};
+
+static int msm8916_wcd_digital_enable_interpolator(
+                                               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:
+               /* apply the digital gain after the interpolator is enabled */
+               usleep_range(10000, 10100);
+               snd_soc_write(codec, rx_gain_reg[w->shift],
+                             snd_soc_read(codec, rx_gain_reg[w->shift]));
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w,
+                                         struct snd_kcontrol *kcontrol,
+                                         int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       unsigned int decimator = w->shift + 1;
+       u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+       u8 dec_hpf_cut_of_freq;
+
+       dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL;
+       tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1);
+       tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Enable TX digital mute */
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK,
+                                   TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
+               dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg) &
+                                       TX_MUX_CTL_CUT_OFF_FREQ_MASK;
+               dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT;
+               if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) {
+                       /* set cut of freq to CF_MIN_3DB_150HZ (0x1) */
+                       snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                           TX_MUX_CTL_CUT_OFF_FREQ_MASK,
+                                           TX_MUX_CTL_CF_NEG_3DB_150HZ);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               /* enable HPF */
+               snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                   TX_MUX_CTL_HPF_BP_SEL_MASK,
+                                   TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS);
+               /* apply the digital gain after the decimator is enabled */
+               snd_soc_write(codec, tx_gain_reg[w->shift],
+                             snd_soc_read(codec, tx_gain_reg[w->shift]));
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK,
+                                   TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
+               snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                   TX_MUX_CTL_HPF_BP_SEL_MASK,
+                                   TX_MUX_CTL_HPF_BP_SEL_BYPASS);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+                                   1 << w->shift);
+               snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+               snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                   TX_MUX_CTL_HPF_BP_SEL_MASK,
+                                   TX_MUX_CTL_HPF_BP_SEL_BYPASS);
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w,
+                                          struct snd_kcontrol *kcontrol,
+                                          int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       unsigned int dmic;
+       int ret;
+       /* get dmic number out of widget name */
+       char *dmic_num = strpbrk(w->name, "12");
+
+       if (dmic_num == NULL) {
+               dev_err(codec->dev, "Invalid DMIC\n");
+               return -EINVAL;
+       }
+       ret = kstrtouint(dmic_num, 10, &dmic);
+       if (ret < 0 || dmic > 2) {
+               dev_err(codec->dev, "Invalid DMIC line on the codec\n");
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, LPASS_CDC_CLK_DMIC_B1_CTL,
+                                   DMIC_B1_CTL_DMIC0_CLK_SEL_MASK,
+                                   DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3);
+               switch (dmic) {
+               case 1:
+                       snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL,
+                                           TXN_DMIC_CTL_CLK_SEL_MASK,
+                                           TXN_DMIC_CTL_CLK_SEL_DIV3);
+                       break;
+               case 2:
+                       snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL,
+                                           TXN_DMIC_CTL_CLK_SEL_MASK,
+                                           TXN_DMIC_CTL_CLK_SEL_DIV3);
+                       break;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = {
+       /*RX stuff */
+       SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("I2S RX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("I2S RX3", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_OUTPUT("PDM_RX1"),
+       SND_SOC_DAPM_OUTPUT("PDM_RX2"),
+       SND_SOC_DAPM_OUTPUT("PDM_RX3"),
+
+       SND_SOC_DAPM_INPUT("LPASS_PDM_TX"),
+
+       SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Interpolator */
+       SND_SOC_DAPM_MIXER_E("RX1 INT", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+                            0, msm8916_wcd_digital_enable_interpolator,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX2 INT", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+                            0, msm8916_wcd_digital_enable_interpolator,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX3 INT", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+                            0, msm8916_wcd_digital_enable_interpolator,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx_mix1_inp1_mux),
+       SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+                        &rx_mix1_inp2_mux),
+       SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+                        &rx_mix1_inp3_mux),
+       SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx2_mix1_inp1_mux),
+       SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+                        &rx2_mix1_inp2_mux),
+       SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+                        &rx2_mix1_inp3_mux),
+       SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx3_mix1_inp1_mux),
+       SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+                        &rx3_mix1_inp2_mux),
+       SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+                        &rx3_mix1_inp3_mux),
+
+       /* TX */
+       SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+                          &dec1_mux, msm8916_wcd_digital_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+                          &dec2_mux, msm8916_wcd_digital_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_AIF_OUT("I2S TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S TX2", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S TX3", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+       /* Digital Mic Inputs */
+       SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+                          msm8916_wcd_digital_enable_dmic,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+                          msm8916_wcd_digital_enable_dmic,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("DMIC_CLK", LPASS_CDC_CLK_DMIC_B1_CTL, 0, 0,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL,
+                           4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0,
+                           NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PDM_CLK", LPASS_CDC_CLK_PDM_CTL, 0, 0, NULL, 0),
+       /* Connectivity Clock */
+       SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0,
+                             NULL, 0),
+
+};
+
+static int msm8916_wcd_digital_get_clks(struct platform_device *pdev,
+                                       struct msm8916_wcd_digital_priv *priv)
+{
+       struct device *dev = &pdev->dev;
+
+       priv->ahbclk = devm_clk_get(dev, "ahbix-clk");
+       if (IS_ERR(priv->ahbclk)) {
+               dev_err(dev, "failed to get ahbix clk\n");
+               return PTR_ERR(priv->ahbclk);
+       }
+
+       priv->mclk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(priv->mclk)) {
+               dev_err(dev, "failed to get mclk\n");
+               return PTR_ERR(priv->mclk);
+       }
+
+       return 0;
+}
+
+static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec)
+{
+       struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(codec->dev);
+
+       snd_soc_codec_set_drvdata(codec, priv);
+
+       return 0;
+}
+
+static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream,
+                                        struct snd_pcm_hw_params *params,
+                                        struct snd_soc_dai *dai)
+{
+       u8 tx_fs_rate;
+       u8 rx_fs_rate;
+
+       switch (params_rate(params)) {
+       case 8000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ;
+               rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ;
+               break;
+       case 16000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ;
+               rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ;
+               break;
+       case 32000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ;
+               rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ;
+               break;
+       case 48000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ;
+               rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ;
+               break;
+       default:
+               dev_err(dai->codec->dev, "Invalid sampling rate %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_CAPTURE:
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+                                   TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate);
+               break;
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+                                   RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+                                   TX_I2S_CTL_TX_I2S_MODE_MASK,
+                                   TX_I2S_CTL_TX_I2S_MODE_16);
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+                                   RX_I2S_CTL_RX_I2S_MODE_MASK,
+                                   RX_I2S_CTL_RX_I2S_MODE_16);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+                                   TX_I2S_CTL_TX_I2S_MODE_MASK,
+                                   TX_I2S_CTL_TX_I2S_MODE_32);
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+                                   RX_I2S_CTL_RX_I2S_MODE_MASK,
+                                   RX_I2S_CTL_RX_I2S_MODE_32);
+               break;
+       default:
+               dev_err(dai->dev, "%s: wrong format selected\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = {
+
+       {"I2S RX1",  NULL, "AIF1 Playback"},
+       {"I2S RX2",  NULL, "AIF1 Playback"},
+       {"I2S RX3",  NULL, "AIF1 Playback"},
+
+       {"AIF1 Capture", NULL, "I2S TX1"},
+       {"AIF1 Capture", NULL, "I2S TX2"},
+       {"AIF1 Capture", NULL, "I2S TX3"},
+
+       /* Decimator Inputs */
+       {"DEC1 MUX", "DMIC1", "DMIC1"},
+       {"DEC1 MUX", "DMIC2", "DMIC2"},
+       {"DEC1 MUX", "ADC1", "ADC1"},
+       {"DEC1 MUX", "ADC2", "ADC2"},
+       {"DEC1 MUX", "ADC3", "ADC3"},
+       {"DEC1 MUX", NULL, "CDC_CONN"},
+
+       {"DEC2 MUX", "DMIC1", "DMIC1"},
+       {"DEC2 MUX", "DMIC2", "DMIC2"},
+       {"DEC2 MUX", "ADC1", "ADC1"},
+       {"DEC2 MUX", "ADC2", "ADC2"},
+       {"DEC2 MUX", "ADC3", "ADC3"},
+       {"DEC2 MUX", NULL, "CDC_CONN"},
+
+       {"DMIC1", NULL, "DMIC_CLK"},
+       {"DMIC2", NULL, "DMIC_CLK"},
+
+       {"I2S TX1", NULL, "DEC1 MUX"},
+       {"I2S TX2", NULL, "DEC2 MUX"},
+
+       {"I2S TX1", NULL, "TX_I2S_CLK"},
+       {"I2S TX2", NULL, "TX_I2S_CLK"},
+
+       {"TX_I2S_CLK", NULL, "MCLK"},
+       {"TX_I2S_CLK", NULL, "PDM_CLK"},
+
+       {"ADC1", NULL, "LPASS_PDM_TX"},
+       {"ADC2", NULL, "LPASS_PDM_TX"},
+       {"ADC3", NULL, "LPASS_PDM_TX"},
+
+       {"I2S RX1", NULL, "RX_I2S_CLK"},
+       {"I2S RX2", NULL, "RX_I2S_CLK"},
+       {"I2S RX3", NULL, "RX_I2S_CLK"},
+
+       {"RX_I2S_CLK", NULL, "PDM_CLK"},
+       {"RX_I2S_CLK", NULL, "MCLK"},
+       {"RX_I2S_CLK", NULL, "CDC_CONN"},
+
+       /* RX1 PATH.. */
+       {"PDM_RX1", NULL, "RX1 INT"},
+       {"RX1 INT", NULL, "RX1 MIX1"},
+
+       {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+       {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+       {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+
+       {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
+       {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
+       {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
+
+       {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
+       {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
+       {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
+
+       {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
+       {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
+       {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
+
+       /* RX2 PATH */
+       {"PDM_RX2", NULL, "RX2 INT"},
+       {"RX2 INT", NULL, "RX2 MIX1"},
+
+       {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+       {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+       {"RX2 MIX1", NULL, "RX2 MIX1 INP3"},
+
+       {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
+       {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
+       {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
+
+       {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
+       {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
+       {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
+
+       {"RX2 MIX1 INP3", "RX1", "I2S RX1"},
+       {"RX2 MIX1 INP3", "RX2", "I2S RX2"},
+       {"RX2 MIX1 INP3", "RX3", "I2S RX3"},
+
+       /* RX3 PATH */
+       {"PDM_RX3", NULL, "RX3 INT"},
+       {"RX3 INT", NULL, "RX3 MIX1"},
+
+       {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+       {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+       {"RX3 MIX1", NULL, "RX3 MIX1 INP3"},
+
+       {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
+       {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
+       {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
+
+       {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
+       {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
+       {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
+
+       {"RX3 MIX1 INP3", "RX1", "I2S RX1"},
+       {"RX3 MIX1 INP3", "RX2", "I2S RX2"},
+       {"RX3 MIX1 INP3", "RX3", "I2S RX3"},
+
+};
+
+static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream,
+                                      struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct msm8916_wcd_digital_priv *msm8916_wcd;
+       unsigned long mclk_rate;
+
+       msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+       snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL,
+                           MCLK_CTL_MCLK_EN_MASK,
+                           MCLK_CTL_MCLK_EN_ENABLE);
+       snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL,
+                           LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK,
+                           LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB);
+
+       mclk_rate = clk_get_rate(msm8916_wcd->mclk);
+       switch (mclk_rate) {
+       case 12288000:
+               snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL,
+                                   TOP_CTL_DIG_MCLK_FREQ_MASK,
+                                   TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ);
+               break;
+       case 9600000:
+               snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL,
+                                   TOP_CTL_DIG_MCLK_FREQ_MASK,
+                                   TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ);
+               break;
+       default:
+               dev_err(codec->dev, "Invalid mclk rate %ld\n", mclk_rate);
+               break;
+       }
+       return 0;
+}
+
+static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream,
+                                        struct snd_soc_dai *dai)
+{
+       snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_PDM_CTL,
+                           LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0);
+}
+
+static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = {
+       .startup = msm8916_wcd_digital_startup,
+       .shutdown = msm8916_wcd_digital_shutdown,
+       .hw_params = msm8916_wcd_digital_hw_params,
+};
+
+static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = {
+       [0] = {
+              .name = "msm8916_wcd_digital_i2s_rx1",
+              .id = 0,
+              .playback = {
+                           .stream_name = "AIF1 Playback",
+                           .rates = MSM8916_WCD_DIGITAL_RATES,
+                           .formats = MSM8916_WCD_DIGITAL_FORMATS,
+                           .channels_min = 1,
+                           .channels_max = 3,
+                           },
+              .ops = &msm8916_wcd_digital_dai_ops,
+              },
+       [1] = {
+              .name = "msm8916_wcd_digital_i2s_tx1",
+              .id = 1,
+              .capture = {
+                          .stream_name = "AIF1 Capture",
+                          .rates = MSM8916_WCD_DIGITAL_RATES,
+                          .formats = MSM8916_WCD_DIGITAL_FORMATS,
+                          .channels_min = 1,
+                          .channels_max = 4,
+                          },
+              .ops = &msm8916_wcd_digital_dai_ops,
+              },
+};
+
+static struct snd_soc_codec_driver msm8916_wcd_digital = {
+       .probe = msm8916_wcd_digital_codec_probe,
+       .component_driver = {
+               .controls = msm8916_wcd_digital_snd_controls,
+               .num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls),
+               .dapm_widgets = msm8916_wcd_digital_dapm_widgets,
+               .num_dapm_widgets =
+                                ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets),
+               .dapm_routes = msm8916_wcd_digital_audio_map,
+               .num_dapm_routes = ARRAY_SIZE(msm8916_wcd_digital_audio_map),
+       },
+};
+
+static const struct regmap_config msm8916_codec_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = LPASS_CDC_TX2_DMIC_CTL,
+       .cache_type = REGCACHE_FLAT,
+};
+
+static int msm8916_wcd_digital_probe(struct platform_device *pdev)
+{
+       struct msm8916_wcd_digital_priv *priv;
+       struct device *dev = &pdev->dev;
+       void __iomem *base;
+       struct resource *mem_res;
+       struct regmap *digital_map;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, mem_res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       digital_map =
+           devm_regmap_init_mmio(&pdev->dev, base,
+                                 &msm8916_codec_regmap_config);
+       if (IS_ERR(digital_map))
+               return PTR_ERR(digital_map);
+
+       ret = msm8916_wcd_digital_get_clks(pdev, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = clk_prepare_enable(priv->ahbclk);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable ahbclk %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(priv->mclk);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable mclk %d\n", ret);
+               return ret;
+       }
+
+       dev_set_drvdata(dev, priv);
+
+       return snd_soc_register_codec(dev, &msm8916_wcd_digital,
+                                     msm8916_wcd_digital_dai,
+                                     ARRAY_SIZE(msm8916_wcd_digital_dai));
+}
+
+static int msm8916_wcd_digital_remove(struct platform_device *pdev)
+{
+       struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_codec(&pdev->dev);
+       clk_disable_unprepare(priv->mclk);
+       clk_disable_unprepare(priv->ahbclk);
+
+       return 0;
+}
+
+static const struct of_device_id msm8916_wcd_digital_match_table[] = {
+       { .compatible = "qcom,msm8916-wcd-digital-codec" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, msm8916_wcd_digital_match_table);
+
+static struct platform_driver msm8916_wcd_digital_driver = {
+       .driver = {
+                  .name = "msm8916-wcd-digital-codec",
+                  .of_match_table = msm8916_wcd_digital_match_table,
+       },
+       .probe = msm8916_wcd_digital_probe,
+       .remove = msm8916_wcd_digital_remove,
+};
+
+module_platform_driver(msm8916_wcd_digital_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("MSM8916 WCD Digital Codec driver");
+MODULE_LICENSE("GPL v2");
index e643be91d7620f786803da5647b65932a4137785..efe3a44658d5a5e6d3a82d5f23ed8f8afd190d5a 100644 (file)
@@ -43,6 +43,8 @@
 #define GAIN_AUGMENT 22500
 #define SIDETONE_BASE 207000
 
+/* the maximum frequency of CLK_ADC and CLK_DAC */
+#define CLK_DA_AD_MAX 6144000
 
 static int nau8825_configure_sysclk(struct nau8825 *nau8825,
                int clk_id, unsigned int freq);
@@ -95,6 +97,27 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = {
        { 8, 0x3 },
 };
 
+/* over sampling rate */
+struct nau8825_osr_attr {
+       unsigned int osr;
+       unsigned int clk_src;
+};
+
+static const struct nau8825_osr_attr osr_dac_sel[] = {
+       { 64, 2 },      /* OSR 64, SRC 1/4 */
+       { 256, 0 },     /* OSR 256, SRC 1 */
+       { 128, 1 },     /* OSR 128, SRC 1/2 */
+       { 0, 0 },
+       { 32, 3 },      /* OSR 32, SRC 1/8 */
+};
+
+static const struct nau8825_osr_attr osr_adc_sel[] = {
+       { 32, 3 },      /* OSR 32, SRC 1/8 */
+       { 64, 2 },      /* OSR 64, SRC 1/4 */
+       { 128, 1 },     /* OSR 128, SRC 1/2 */
+       { 256, 0 },     /* OSR 256, SRC 1 */
+};
+
 static const struct reg_default nau8825_reg_defaults[] = {
        { NAU8825_REG_ENA_CTRL, 0x00ff },
        { NAU8825_REG_IIC_ADDR_SET, 0x0 },
@@ -1179,15 +1202,64 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {
        {"HPOR", NULL, "Class G"},
 };
 
+static int nau8825_clock_check(struct nau8825 *nau8825,
+       int stream, int rate, int osr)
+{
+       int osrate;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (osr >= ARRAY_SIZE(osr_dac_sel))
+                       return -EINVAL;
+               osrate = osr_dac_sel[osr].osr;
+       } else {
+               if (osr >= ARRAY_SIZE(osr_adc_sel))
+                       return -EINVAL;
+               osrate = osr_adc_sel[osr].osr;
+       }
+
+       if (!osrate || rate * osr > CLK_DA_AD_MAX) {
+               dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int nau8825_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
        struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val_len = 0;
+       unsigned int val_len = 0, osr;
+
+       nau8825_sema_acquire(nau8825, 3 * HZ);
 
-       nau8825_sema_acquire(nau8825, 2 * HZ);
+       /* CLK_DAC or CLK_ADC = OSR * FS
+        * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR)
+        * multiplied by the audio sample rate (Fs). Note that the OSR and Fs
+        * values must be selected such that the maximum frequency is less
+        * than 6.144 MHz.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr);
+               osr &= NAU8825_DAC_OVERSAMPLE_MASK;
+               if (nau8825_clock_check(nau8825, substream->stream,
+                       params_rate(params), osr))
+                       return -EINVAL;
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+                       NAU8825_CLK_DAC_SRC_MASK,
+                       osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT);
+       } else {
+               regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr);
+               osr &= NAU8825_ADC_SYNC_DOWN_MASK;
+               if (nau8825_clock_check(nau8825, substream->stream,
+                       params_rate(params), osr))
+                       return -EINVAL;
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
+                       NAU8825_CLK_ADC_SRC_MASK,
+                       osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT);
+       }
 
        switch (params_width(params)) {
        case 16:
@@ -1221,7 +1293,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
        unsigned int ctrl1_val = 0, ctrl2_val = 0;
 
-       nau8825_sema_acquire(nau8825, 2 * HZ);
+       nau8825_sema_acquire(nau8825, 3 * HZ);
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
@@ -1774,9 +1846,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
         * (audible hiss). Set it to something better.
         */
        regmap_update_bits(regmap, NAU8825_REG_ADC_RATE,
-               NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128);
+               NAU8825_ADC_SYNC_DOWN_MASK | NAU8825_ADC_SINC4_EN,
+               NAU8825_ADC_SYNC_DOWN_64);
        regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
-               NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128);
+               NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64);
        /* Disable DACR/L power */
        regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
                NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
@@ -1811,6 +1884,9 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
                NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_L);
        regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL,
                NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_R);
+       /* Disable short Frame Sync detection logic */
+       regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT,
+               NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET);
 }
 
 static const struct regmap_config nau8825_regmap_config = {
@@ -1919,8 +1995,10 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
        regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER,
                NAU8825_CLK_SRC_MASK | NAU8825_CLK_MCLK_SRC_MASK,
                NAU8825_CLK_SRC_MCLK | fll_param->mclk_src);
+       /* Make DSP operate at high speed for better performance. */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1,
-                       NAU8825_FLL_RATIO_MASK, fll_param->ratio);
+               NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK,
+               fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT));
        /* FLL 16-bit fractional input */
        regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac);
        /* FLL 10-bit integer input */
@@ -1936,19 +2014,22 @@ static void nau8825_fll_apply(struct nau8825 *nau8825,
        regmap_update_bits(nau8825->regmap,
                NAU8825_REG_FLL6, NAU8825_DCO_EN, 0);
        if (fll_param->fll_frac) {
+               /* set FLL loop filter enable and cutoff frequency at 500Khz */
                regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
                        NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
                        NAU8825_FLL_FTR_SW_MASK,
                        NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
                        NAU8825_FLL_FTR_SW_FILTER);
                regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6,
-                       NAU8825_SDM_EN, NAU8825_SDM_EN);
+                       NAU8825_SDM_EN | NAU8825_CUTOFF500,
+                       NAU8825_SDM_EN | NAU8825_CUTOFF500);
        } else {
+               /* disable FLL loop filter and cutoff frequency */
                regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
                        NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN |
                        NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_FTR_SW_ACCU);
-               regmap_update_bits(nau8825->regmap,
-                       NAU8825_REG_FLL6, NAU8825_SDM_EN, 0);
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6,
+                       NAU8825_SDM_EN | NAU8825_CUTOFF500, 0);
        }
 }
 
@@ -2014,6 +2095,9 @@ static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap)
                NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK);
        regmap_update_bits(regmap, NAU8825_REG_FLL6,
                NAU8825_DCO_EN, 0);
+       /* Make DSP operate as default setting for power saving. */
+       regmap_update_bits(regmap, NAU8825_REG_FLL1,
+               NAU8825_ICTRL_LATCH_MASK, 0);
 }
 
 static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
@@ -2038,7 +2122,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
                nau8825_configure_mclk_as_sysclk(regmap);
                /* MCLK not changed by clock tree */
                regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
@@ -2057,10 +2141,13 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                                NAU8825_DCO_EN, NAU8825_DCO_EN);
                        regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
                                NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO);
-                       /* Decrease the VCO frequency for power saving */
+                       /* Decrease the VCO frequency and make DSP operate
+                        * as default setting for power saving.
+                        */
                        regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER,
                                NAU8825_CLK_MCLK_SRC_MASK, 0xf);
                        regmap_update_bits(regmap, NAU8825_REG_FLL1,
+                               NAU8825_ICTRL_LATCH_MASK |
                                NAU8825_FLL_RATIO_MASK, 0x10);
                        regmap_update_bits(regmap, NAU8825_REG_FLL6,
                                NAU8825_SDM_EN, NAU8825_SDM_EN);
@@ -2083,9 +2170,14 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
+               /* Higher FLL reference input frequency can only set lower
+                * gain error, such as 0000 for input reference from MCLK
+                * 12.288Mhz.
+                */
                regmap_update_bits(regmap, NAU8825_REG_FLL3,
-                       NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_MCLK);
+                       NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+                       NAU8825_FLL_CLK_SRC_MCLK | 0);
                /* Release the semaphone. */
                nau8825_sema_release(nau8825);
 
@@ -2100,9 +2192,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
+               /* If FLL reference input is from low frequency source,
+                * higher error gain can apply such as 0xf which has
+                * the most sensitive gain error correction threshold,
+                * Therefore, FLL has the most accurate DCO to
+                * target frequency.
+                */
                regmap_update_bits(regmap, NAU8825_REG_FLL3,
-                       NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_BLK);
+                       NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+                       NAU8825_FLL_CLK_SRC_BLK |
+                       (0xf << NAU8825_GAIN_ERR_SFT));
                /* Release the semaphone. */
                nau8825_sema_release(nau8825);
 
@@ -2118,9 +2218,17 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id,
                 * fered by cross talk process, the driver make the playback
                 * preparation halted until cross talk process finish.
                 */
-               nau8825_sema_acquire(nau8825, 2 * HZ);
+               nau8825_sema_acquire(nau8825, 3 * HZ);
+               /* If FLL reference input is from low frequency source,
+                * higher error gain can apply such as 0xf which has
+                * the most sensitive gain error correction threshold,
+                * Therefore, FLL has the most accurate DCO to
+                * target frequency.
+                */
                regmap_update_bits(regmap, NAU8825_REG_FLL3,
-                       NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_FS);
+                       NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK,
+                       NAU8825_FLL_CLK_SRC_FS |
+                       (0xf << NAU8825_GAIN_ERR_SFT));
                /* Release the semaphone. */
                nau8825_sema_release(nau8825);
 
index 1c63e2abafa99cddc7f9a2577e0e088803a68214..5d1704e732415dd04134f44ddab9971156c97de1 100644 (file)
 #define NAU8825_CLK_SRC_MASK                   (1 << NAU8825_CLK_SRC_SFT)
 #define NAU8825_CLK_SRC_VCO                    (1 << NAU8825_CLK_SRC_SFT)
 #define NAU8825_CLK_SRC_MCLK                   (0 << NAU8825_CLK_SRC_SFT)
+#define NAU8825_CLK_ADC_SRC_SFT                6
+#define NAU8825_CLK_ADC_SRC_MASK               (0x3 << NAU8825_CLK_ADC_SRC_SFT)
+#define NAU8825_CLK_DAC_SRC_SFT                4
+#define NAU8825_CLK_DAC_SRC_MASK               (0x3 << NAU8825_CLK_DAC_SRC_SFT)
 #define NAU8825_CLK_MCLK_SRC_MASK              (0xf << 0)
 
 /* FLL1 (0x04) */
+#define NAU8825_ICTRL_LATCH_SFT        10
+#define NAU8825_ICTRL_LATCH_MASK       (0x7 << NAU8825_ICTRL_LATCH_SFT)
 #define NAU8825_FLL_RATIO_MASK                 (0x7f << 0)
 
 /* FLL3 (0x06) */
+#define NAU8825_GAIN_ERR_SFT                   12
+#define NAU8825_GAIN_ERR_MASK                  (0xf << NAU8825_GAIN_ERR_SFT)
 #define NAU8825_FLL_INTEGER_MASK               (0x3ff << 0)
 #define NAU8825_FLL_CLK_SRC_SFT                10
 #define NAU8825_FLL_CLK_SRC_MASK               (0x3 << NAU8825_FLL_CLK_SRC_SFT)
 /* FLL6 (0x9) */
 #define NAU8825_DCO_EN                         (0x1 << 15)
 #define NAU8825_SDM_EN                         (0x1 << 14)
+#define NAU8825_CUTOFF500                      (0x1 << 13)
 
 /* HSD_CTRL (0xc) */
 #define NAU8825_HSD_AUTO_MODE  (1 << 6)
 #define NAU8825_I2S_MS_SLAVE   (0 << NAU8825_I2S_MS_SFT)
 #define NAU8825_I2S_BLK_DIV_MASK       0x7
 
+/* LEFT_TIME_SLOT (0x1e) */
+#define NAU8825_FS_ERR_CMP_SEL_SFT     14
+#define NAU8825_FS_ERR_CMP_SEL_MASK    (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT)
+#define NAU8825_DIS_FS_SHORT_DET       (1 << 13)
+
 /* BIQ_CTRL (0x20) */
 #define NAU8825_BIQ_WRT_SFT   4
 #define NAU8825_BIQ_WRT_EN     (1 << NAU8825_BIQ_WRT_SFT)
 #define NAU8825_BIQ_PATH_DAC   (1 << NAU8825_BIQ_PATH_SFT)
 
 /* ADC_RATE (0x2b) */
+#define NAU8825_ADC_SINC4_SFT          4
+#define NAU8825_ADC_SINC4_EN           (1 << NAU8825_ADC_SINC4_SFT)
 #define NAU8825_ADC_SYNC_DOWN_SFT      0
 #define NAU8825_ADC_SYNC_DOWN_MASK     0x3
 #define NAU8825_ADC_SYNC_DOWN_32       0
index 1dc68ab08a1799e71ec17677c5b0da959d3cd40f..7b447d0b173a8c1860c2ff2b08a51e790887fb41 100644 (file)
@@ -102,6 +102,7 @@ struct pll_calc_map {
 };
 
 static const struct pll_calc_map pll_preset_table[] = {
+       {19200000,  4096000,  23, 14, 1, false},
        {19200000,  24576000,  3, 30, 3, false},
 };
 
index a4b910efbd455eba52f086053ea9a6ec4789ef03..8f571cf8edd4d0c6cb93aaefb640771c1a6a2442 100644 (file)
@@ -51,7 +51,7 @@ int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)
        if (ret == 4)
                return 0;
        else
-               pr_err("ret=%d\n", ret);
+               dev_err(&client->dev, "I2C error %d\n", ret);
        if (ret < 0)
                return ret;
        else
index 55558643166fda708ccb781daffcc9ed40806bc2..7150a407ffd9d9e8590e83a9673d36781cf76bf1 100644 (file)
@@ -249,6 +249,11 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic)
                        snd_soc_dapm_force_enable_pin(dapm, "LDO1");
                        snd_soc_dapm_sync(dapm);
 
+                       regmap_update_bits(rt298->regmap,
+                               RT298_POWER_CTRL1, 0x1001, 0);
+                       regmap_update_bits(rt298->regmap,
+                               RT298_POWER_CTRL2, 0x4, 0x4);
+
                        regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24);
                        msleep(50);
 
@@ -321,11 +326,31 @@ static void rt298_jack_detect_work(struct work_struct *work)
 int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 {
        struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm;
+       bool hp = false;
+       bool mic = false;
+       int status = 0;
+
+       /* If jack in NULL, disable HS jack */
+       if (!jack) {
+               regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0);
+               dapm = snd_soc_codec_get_dapm(codec);
+               snd_soc_dapm_disable_pin(dapm, "LDO1");
+               snd_soc_dapm_sync(dapm);
+               return 0;
+       }
 
        rt298->jack = jack;
+       regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2);
+
+       rt298_jack_detect(rt298, &hp, &mic);
+       if (hp == true)
+               status |= SND_JACK_HEADPHONE;
 
-       /* Send an initial empty report */
-       snd_soc_jack_report(rt298->jack, 0,
+       if (mic == true)
+               status |= SND_JACK_MICROPHONE;
+
+       snd_soc_jack_report(rt298->jack, status,
                SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
 
        return 0;
index 09103aab0cb2639486cb59f746619c9ea743890a..0901e25d6db60b770a985054ccd70b52efa30426 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/sched.h>
-#include <linux/kthread.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
 #include <linux/regulator/consumer.h>
index f24b7cfd3a89fabab6f3c92d2907931a00e028b7..b281a46d769dc25165a7bb6073ec72d4a302fafd 100644 (file)
@@ -452,6 +452,9 @@ static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w,
                        RT5514_CLK_DMIC_OUT_SEL_MASK,
                        idx << RT5514_CLK_DMIC_OUT_SEL_SFT);
 
+       if (rt5514->pdata.dmic_init_delay)
+               msleep(rt5514->pdata.dmic_init_delay);
+
        return idx;
 }
 
@@ -1073,9 +1076,18 @@ static const struct of_device_id rt5514_of_match[] = {
 MODULE_DEVICE_TABLE(of, rt5514_of_match);
 #endif
 
+static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev)
+{
+       device_property_read_u32(dev, "realtek,dmic-init-delay-ms",
+               &rt5514->pdata.dmic_init_delay);
+
+       return 0;
+}
+
 static int rt5514_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
+       struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct rt5514_priv *rt5514;
        int ret;
        unsigned int val;
@@ -1087,6 +1099,11 @@ static int rt5514_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, rt5514);
 
+       if (pdata)
+               rt5514->pdata = *pdata;
+       else if (i2c->dev.of_node)
+               rt5514_parse_dt(rt5514, &i2c->dev);
+
        rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap);
        if (IS_ERR(rt5514->i2c_regmap)) {
                ret = PTR_ERR(rt5514->i2c_regmap);
index 229de0e2c88c614695b5bab80d18e7b5ac1dbd62..5d343fb6d125d46e8fe463f1b1f7485428911c92 100644 (file)
@@ -13,6 +13,7 @@
 #define __RT5514_H__
 
 #include <linux/clk.h>
+#include <sound/rt5514.h>
 
 #define RT5514_DEVICE_ID                       0x10ec5514
 
@@ -243,6 +244,7 @@ enum {
 };
 
 struct rt5514_priv {
+       struct rt5514_platform_data pdata;
        struct snd_soc_codec *codec;
        struct regmap *i2c_regmap, *regmap;
        struct clk *mclk;
index d1f273b249910038c7e45003cd51a25e81273ebf..7d6e0823f98f12023d2e2f95a7734ec51a6bef68 100644 (file)
@@ -960,8 +960,7 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec);
        unsigned int val_len = 0, val_clk, mask_clk;
        int pre_div, bclk_ms, frame_size;
index 3cc1135fc2cd1cba29a5c39b5060b3899abe90df..e29a6defefa006dda473856fb30ca64ba152bdd9 100644 (file)
@@ -423,6 +423,8 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {
        SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL,
                        RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
                        127, 0, adc_vol_tlv),
+       SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1,
+               RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1),
        SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA,
                        RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
                        127, 0, adc_vol_tlv),
@@ -2407,6 +2409,9 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
        if (ret != 0)
                dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
+       regmap_update_bits(rt5640->regmap, RT5640_DUMMY1,
+                               RT5640_MCLK_DET, RT5640_MCLK_DET);
+
        if (rt5640->pdata.in1_diff)
                regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
                                        RT5640_IN_DF1, RT5640_IN_DF1);
index 90c88711c72a227a2442d0a93e82782fb3439770..b8a811732a52ebb408a2787740dd449b7be9b3c6 100644 (file)
 #define RT5640_ZCD_HP_DIS                      (0x0 << 15)
 #define RT5640_ZCD_HP_EN                       (0x1 << 15)
 
+/* General Control 1 (0xfa) */
+#define RT5640_M_MONO_ADC_L                    (0x1 << 13)
+#define RT5640_M_MONO_ADC_L_SFT                        13
+#define RT5640_M_MONO_ADC_R                    (0x1 << 12)
+#define RT5640_M_MONO_ADC_R_SFT                        12
+#define RT5640_MCLK_DET                                (0x1 << 11)
 
 /* Codec Private Register definition */
 /* 3D Speaker Control (0x63) */
index 9f0933ced8049fa8c9d6be0b8d65491662988cc8..76cf76a2e9b6d1865c18da567d18c58b6f1880ad 100644 (file)
@@ -1311,6 +1311,10 @@ static int rt5660_i2c_probe(struct i2c_client *i2c,
        if (ret != 0)
                dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
+       regmap_update_bits(rt5660->regmap, RT5660_GEN_CTRL1,
+               RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET,
+               RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET);
+
        if (rt5660->pdata.dmic1_data_pin) {
                regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1,
                        RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL);
index 6cdb9269ec9e0fb3d8a781a689dc1f65b4b0116e..bba18fb66b6f7685dc883c4671c416e2bed7d0f1 100644 (file)
 /* General Control 1 (0xfa) */
 #define RT5660_PWR_VREF_HP                     (0x1 << 11)
 #define RT5660_PWR_VREF_HP_SFT                 11
+#define RT5660_AUTO_DIS_AMP                    (0x1 << 6)
+#define RT5660_MCLK_DET                                (0x1 << 5)
+#define RT5660_POW_CLKDET                      (0x1 << 1)
 #define RT5660_DIG_GATE_CTRL                   (0x1)
 #define RT5660_DIG_GATE_CTRL_SFT               0
 
index ff968d93f31f0571e832d79d47f5a2596537b8ab..a32508d7dcfd8a78e6510dc3db0ef546923a407b 100644 (file)
@@ -1547,11 +1547,11 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert)
                        msleep(sleep_time[i]);
                        val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) &
                                0x0003;
+                       dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
+                               __func__, val, sleep_time[i]);
                        i++;
                        if (val == 0x1 || val == 0x2 || val == 0x3)
                                break;
-                       dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n",
-                               __func__, val, sleep_time[i]);
                }
                dev_dbg(codec->dev, "%s val = %d\n", __func__, val);
                switch (val) {
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
new file mode 100644 (file)
index 0000000..34254fd
--- /dev/null
@@ -0,0 +1,4875 @@
+/*
+ * rt5665.c  --  RT5665/RT5658 ALSA SoC audio codec driver
+ *
+ * Copyright 2016 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5665.h>
+
+#include "rl6231.h"
+#include "rt5665.h"
+
+#define RT5665_NUM_SUPPLIES 3
+
+static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = {
+       "AVDD",
+       "MICVDD",
+       "VBAT",
+};
+
+struct rt5665_priv {
+       struct snd_soc_codec *codec;
+       struct rt5665_platform_data pdata;
+       struct regmap *regmap;
+       struct gpio_desc *gpiod_ldo1_en;
+       struct gpio_desc *gpiod_reset;
+       struct snd_soc_jack *hs_jack;
+       struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES];
+       struct delayed_work jack_detect_work;
+       struct delayed_work calibrate_work;
+       struct delayed_work jd_check_work;
+       struct mutex calibrate_mutex;
+
+       int sysclk;
+       int sysclk_src;
+       int lrck[RT5665_AIFS];
+       int bclk[RT5665_AIFS];
+       int master[RT5665_AIFS];
+       int id;
+
+       int pll_src;
+       int pll_in;
+       int pll_out;
+
+       int jack_type;
+       int irq_work_delay_time;
+       unsigned int sar_adc_value;
+};
+
+static const struct reg_default rt5665_reg[] = {
+       {0x0000, 0x0000},
+       {0x0001, 0xc8c8},
+       {0x0002, 0x8080},
+       {0x0003, 0x8000},
+       {0x0004, 0xc80a},
+       {0x0005, 0x0000},
+       {0x0006, 0x0000},
+       {0x0007, 0x0000},
+       {0x000a, 0x0000},
+       {0x000b, 0x0000},
+       {0x000c, 0x0000},
+       {0x000d, 0x0000},
+       {0x000f, 0x0808},
+       {0x0010, 0x4040},
+       {0x0011, 0x0000},
+       {0x0012, 0x1404},
+       {0x0013, 0x1000},
+       {0x0014, 0xa00a},
+       {0x0015, 0x0404},
+       {0x0016, 0x0404},
+       {0x0017, 0x0011},
+       {0x0018, 0xafaf},
+       {0x0019, 0xafaf},
+       {0x001a, 0xafaf},
+       {0x001b, 0x0011},
+       {0x001c, 0x2f2f},
+       {0x001d, 0x2f2f},
+       {0x001e, 0x2f2f},
+       {0x001f, 0x0000},
+       {0x0020, 0x0000},
+       {0x0021, 0x0000},
+       {0x0022, 0x5757},
+       {0x0023, 0x0039},
+       {0x0026, 0xc0c0},
+       {0x0027, 0xc0c0},
+       {0x0028, 0xc0c0},
+       {0x0029, 0x8080},
+       {0x002a, 0xaaaa},
+       {0x002b, 0xaaaa},
+       {0x002c, 0xaba8},
+       {0x002d, 0x0000},
+       {0x002e, 0x0000},
+       {0x002f, 0x0000},
+       {0x0030, 0x0000},
+       {0x0031, 0x5000},
+       {0x0032, 0x0000},
+       {0x0033, 0x0000},
+       {0x0034, 0x0000},
+       {0x0035, 0x0000},
+       {0x003a, 0x0000},
+       {0x003b, 0x0000},
+       {0x003c, 0x00ff},
+       {0x003d, 0x0000},
+       {0x003e, 0x00ff},
+       {0x003f, 0x0000},
+       {0x0040, 0x0000},
+       {0x0041, 0x00ff},
+       {0x0042, 0x0000},
+       {0x0043, 0x00ff},
+       {0x0044, 0x0c0c},
+       {0x0049, 0xc00b},
+       {0x004a, 0x0000},
+       {0x004b, 0x031f},
+       {0x004d, 0x0000},
+       {0x004e, 0x001f},
+       {0x004f, 0x0000},
+       {0x0050, 0x001f},
+       {0x0052, 0xf000},
+       {0x0061, 0x0000},
+       {0x0062, 0x0000},
+       {0x0063, 0x003e},
+       {0x0064, 0x0000},
+       {0x0065, 0x0000},
+       {0x0066, 0x003f},
+       {0x0067, 0x0000},
+       {0x006b, 0x0000},
+       {0x006d, 0xff00},
+       {0x006e, 0x2808},
+       {0x006f, 0x000a},
+       {0x0070, 0x8000},
+       {0x0071, 0x8000},
+       {0x0072, 0x8000},
+       {0x0073, 0x7000},
+       {0x0074, 0x7770},
+       {0x0075, 0x0002},
+       {0x0076, 0x0001},
+       {0x0078, 0x00f0},
+       {0x0079, 0x0000},
+       {0x007a, 0x0000},
+       {0x007b, 0x0000},
+       {0x007c, 0x0000},
+       {0x007d, 0x0123},
+       {0x007e, 0x4500},
+       {0x007f, 0x8003},
+       {0x0080, 0x0000},
+       {0x0081, 0x0000},
+       {0x0082, 0x0000},
+       {0x0083, 0x0000},
+       {0x0084, 0x0000},
+       {0x0085, 0x0000},
+       {0x0086, 0x0008},
+       {0x0087, 0x0000},
+       {0x0088, 0x0000},
+       {0x0089, 0x0000},
+       {0x008a, 0x0000},
+       {0x008b, 0x0000},
+       {0x008c, 0x0003},
+       {0x008e, 0x0060},
+       {0x008f, 0x1000},
+       {0x0091, 0x0c26},
+       {0x0092, 0x0073},
+       {0x0093, 0x0000},
+       {0x0094, 0x0080},
+       {0x0098, 0x0000},
+       {0x0099, 0x0000},
+       {0x009a, 0x0007},
+       {0x009f, 0x0000},
+       {0x00a0, 0x0000},
+       {0x00a1, 0x0002},
+       {0x00a2, 0x0001},
+       {0x00a3, 0x0002},
+       {0x00a4, 0x0001},
+       {0x00ae, 0x2040},
+       {0x00af, 0x0000},
+       {0x00b6, 0x0000},
+       {0x00b7, 0x0000},
+       {0x00b8, 0x0000},
+       {0x00b9, 0x0000},
+       {0x00ba, 0x0002},
+       {0x00bb, 0x0000},
+       {0x00be, 0x0000},
+       {0x00c0, 0x0000},
+       {0x00c1, 0x0aaa},
+       {0x00c2, 0xaa80},
+       {0x00c3, 0x0003},
+       {0x00c4, 0x0000},
+       {0x00d0, 0x0000},
+       {0x00d1, 0x2244},
+       {0x00d3, 0x3300},
+       {0x00d4, 0x2200},
+       {0x00d9, 0x0809},
+       {0x00da, 0x0000},
+       {0x00db, 0x0008},
+       {0x00dc, 0x00c0},
+       {0x00dd, 0x6724},
+       {0x00de, 0x3131},
+       {0x00df, 0x0008},
+       {0x00e0, 0x4000},
+       {0x00e1, 0x3131},
+       {0x00e2, 0x600c},
+       {0x00ea, 0xb320},
+       {0x00eb, 0x0000},
+       {0x00ec, 0xb300},
+       {0x00ed, 0x0000},
+       {0x00ee, 0xb320},
+       {0x00ef, 0x0000},
+       {0x00f0, 0x0201},
+       {0x00f1, 0x0ddd},
+       {0x00f2, 0x0ddd},
+       {0x00f6, 0x0000},
+       {0x00f7, 0x0000},
+       {0x00f8, 0x0000},
+       {0x00fa, 0x0000},
+       {0x00fb, 0x0000},
+       {0x00fc, 0x0000},
+       {0x00fd, 0x0000},
+       {0x00fe, 0x10ec},
+       {0x00ff, 0x6451},
+       {0x0100, 0xaaaa},
+       {0x0101, 0x000a},
+       {0x010a, 0xaaaa},
+       {0x010b, 0xa0a0},
+       {0x010c, 0xaeae},
+       {0x010d, 0xaaaa},
+       {0x010e, 0xaaaa},
+       {0x010f, 0xaaaa},
+       {0x0110, 0xe002},
+       {0x0111, 0xa402},
+       {0x0112, 0xaaaa},
+       {0x0113, 0x2000},
+       {0x0117, 0x0f00},
+       {0x0125, 0x0410},
+       {0x0132, 0x0000},
+       {0x0133, 0x0000},
+       {0x0137, 0x5540},
+       {0x0138, 0x3700},
+       {0x0139, 0x79a1},
+       {0x013a, 0x2020},
+       {0x013b, 0x2020},
+       {0x013c, 0x2005},
+       {0x013f, 0x0000},
+       {0x0145, 0x0002},
+       {0x0146, 0x0000},
+       {0x0147, 0x0000},
+       {0x0148, 0x0000},
+       {0x0150, 0x0000},
+       {0x0160, 0x4eff},
+       {0x0161, 0x0080},
+       {0x0162, 0x0200},
+       {0x0163, 0x0800},
+       {0x0164, 0x0000},
+       {0x0165, 0x0000},
+       {0x0166, 0x0000},
+       {0x0167, 0x000f},
+       {0x0170, 0x4e87},
+       {0x0171, 0x0080},
+       {0x0172, 0x0200},
+       {0x0173, 0x0800},
+       {0x0174, 0x00ff},
+       {0x0175, 0x0000},
+       {0x0190, 0x413d},
+       {0x0191, 0x4139},
+       {0x0192, 0x4135},
+       {0x0193, 0x413d},
+       {0x0194, 0x0000},
+       {0x0195, 0x0000},
+       {0x0196, 0x0000},
+       {0x0197, 0x0000},
+       {0x0198, 0x0000},
+       {0x0199, 0x0000},
+       {0x01a0, 0x1e64},
+       {0x01a1, 0x06a3},
+       {0x01a2, 0x0000},
+       {0x01a3, 0x0000},
+       {0x01a4, 0x0000},
+       {0x01a5, 0x0000},
+       {0x01a6, 0x0000},
+       {0x01a7, 0x8000},
+       {0x01a8, 0x0000},
+       {0x01a9, 0x0000},
+       {0x01aa, 0x0000},
+       {0x01ab, 0x0000},
+       {0x01b5, 0x0000},
+       {0x01b6, 0x01c3},
+       {0x01b7, 0x02a0},
+       {0x01b8, 0x03e9},
+       {0x01b9, 0x1389},
+       {0x01ba, 0xc351},
+       {0x01bb, 0x0009},
+       {0x01bc, 0x0018},
+       {0x01bd, 0x002a},
+       {0x01be, 0x004c},
+       {0x01bf, 0x0097},
+       {0x01c0, 0x433d},
+       {0x01c1, 0x0000},
+       {0x01c2, 0x0000},
+       {0x01c3, 0x0000},
+       {0x01c4, 0x0000},
+       {0x01c5, 0x0000},
+       {0x01c6, 0x0000},
+       {0x01c7, 0x0000},
+       {0x01c8, 0x40af},
+       {0x01c9, 0x0702},
+       {0x01ca, 0x0000},
+       {0x01cb, 0x0000},
+       {0x01cc, 0x5757},
+       {0x01cd, 0x5757},
+       {0x01ce, 0x5757},
+       {0x01cf, 0x5757},
+       {0x01d0, 0x5757},
+       {0x01d1, 0x5757},
+       {0x01d2, 0x5757},
+       {0x01d3, 0x5757},
+       {0x01d4, 0x5757},
+       {0x01d5, 0x5757},
+       {0x01d6, 0x003c},
+       {0x01da, 0x0000},
+       {0x01db, 0x0000},
+       {0x01dc, 0x0000},
+       {0x01de, 0x7c00},
+       {0x01df, 0x0320},
+       {0x01e0, 0x06a1},
+       {0x01e1, 0x0000},
+       {0x01e2, 0x0000},
+       {0x01e3, 0x0000},
+       {0x01e4, 0x0000},
+       {0x01e6, 0x0001},
+       {0x01e7, 0x0000},
+       {0x01e8, 0x0000},
+       {0x01ea, 0xbf3f},
+       {0x01eb, 0x0000},
+       {0x01ec, 0x0000},
+       {0x01ed, 0x0000},
+       {0x01ee, 0x0000},
+       {0x01ef, 0x0000},
+       {0x01f0, 0x0000},
+       {0x01f1, 0x0000},
+       {0x01f2, 0x0000},
+       {0x01f3, 0x0000},
+       {0x01f4, 0x0000},
+       {0x0200, 0x0000},
+       {0x0201, 0x0000},
+       {0x0202, 0x0000},
+       {0x0203, 0x0000},
+       {0x0204, 0x0000},
+       {0x0205, 0x0000},
+       {0x0206, 0x0000},
+       {0x0207, 0x0000},
+       {0x0208, 0x0000},
+       {0x0210, 0x60b1},
+       {0x0211, 0xa005},
+       {0x0212, 0x024c},
+       {0x0213, 0xf7ff},
+       {0x0214, 0x024c},
+       {0x0215, 0x0102},
+       {0x0216, 0x00a3},
+       {0x0217, 0x0048},
+       {0x0218, 0xa2c0},
+       {0x0219, 0x0400},
+       {0x021a, 0x00c8},
+       {0x021b, 0x00c0},
+       {0x02ff, 0x0110},
+       {0x0300, 0x001f},
+       {0x0301, 0x032c},
+       {0x0302, 0x5f21},
+       {0x0303, 0x4000},
+       {0x0304, 0x4000},
+       {0x0305, 0x06d5},
+       {0x0306, 0x8000},
+       {0x0307, 0x0700},
+       {0x0310, 0x4560},
+       {0x0311, 0xa4a8},
+       {0x0312, 0x7418},
+       {0x0313, 0x0000},
+       {0x0314, 0x0006},
+       {0x0315, 0xffff},
+       {0x0316, 0xc400},
+       {0x0317, 0x0000},
+       {0x0330, 0x00a6},
+       {0x0331, 0x04c3},
+       {0x0332, 0x27c8},
+       {0x0333, 0xbf50},
+       {0x0334, 0x0045},
+       {0x0335, 0x0007},
+       {0x0336, 0x7418},
+       {0x0337, 0x0501},
+       {0x0338, 0x0000},
+       {0x0339, 0x0010},
+       {0x033a, 0x1010},
+       {0x03c0, 0x7e00},
+       {0x03c1, 0x8000},
+       {0x03c2, 0x8000},
+       {0x03c3, 0x8000},
+       {0x03c4, 0x8000},
+       {0x03c5, 0x8000},
+       {0x03c6, 0x8000},
+       {0x03c7, 0x8000},
+       {0x03c8, 0x8000},
+       {0x03c9, 0x8000},
+       {0x03ca, 0x8000},
+       {0x03cb, 0x8000},
+       {0x03cc, 0x8000},
+       {0x03d0, 0x0000},
+       {0x03d1, 0x0000},
+       {0x03d2, 0x0000},
+       {0x03d3, 0x0000},
+       {0x03d4, 0x2000},
+       {0x03d5, 0x2000},
+       {0x03d6, 0x0000},
+       {0x03d7, 0x0000},
+       {0x03d8, 0x2000},
+       {0x03d9, 0x2000},
+       {0x03da, 0x2000},
+       {0x03db, 0x2000},
+       {0x03dc, 0x0000},
+       {0x03dd, 0x0000},
+       {0x03de, 0x0000},
+       {0x03df, 0x2000},
+       {0x03e0, 0x0000},
+       {0x03e1, 0x0000},
+       {0x03e2, 0x0000},
+       {0x03e3, 0x0000},
+       {0x03e4, 0x0000},
+       {0x03e5, 0x0000},
+       {0x03e6, 0x0000},
+       {0x03e7, 0x0000},
+       {0x03e8, 0x0000},
+       {0x03e9, 0x0000},
+       {0x03ea, 0x0000},
+       {0x03eb, 0x0000},
+       {0x03ec, 0x0000},
+       {0x03ed, 0x0000},
+       {0x03ee, 0x0000},
+       {0x03ef, 0x0000},
+       {0x03f0, 0x0800},
+       {0x03f1, 0x0800},
+       {0x03f2, 0x0800},
+       {0x03f3, 0x0800},
+};
+
+static bool rt5665_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case RT5665_RESET:
+       case RT5665_EJD_CTRL_2:
+       case RT5665_GPIO_STA:
+       case RT5665_INT_ST_1:
+       case RT5665_IL_CMD_1:
+       case RT5665_4BTN_IL_CMD_1:
+       case RT5665_PSV_IL_CMD_1:
+       case RT5665_AJD1_CTRL:
+       case RT5665_JD_CTRL_3:
+       case RT5665_STO_NG2_CTRL_1:
+       case RT5665_SAR_IL_CMD_4:
+       case RT5665_DEVICE_ID:
+       case RT5665_STO1_DAC_SIL_DET ... RT5665_STO2_DAC_SIL_DET:
+       case RT5665_MONO_AMP_CALIB_STA1 ... RT5665_MONO_AMP_CALIB_STA6:
+       case RT5665_HP_IMP_SENS_CTRL_12 ... RT5665_HP_IMP_SENS_CTRL_15:
+       case RT5665_HP_CALIB_STA_1 ... RT5665_HP_CALIB_STA_11:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt5665_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case RT5665_RESET:
+       case RT5665_VENDOR_ID:
+       case RT5665_VENDOR_ID_1:
+       case RT5665_DEVICE_ID:
+       case RT5665_LOUT:
+       case RT5665_HP_CTRL_1:
+       case RT5665_HP_CTRL_2:
+       case RT5665_MONO_OUT:
+       case RT5665_HPL_GAIN:
+       case RT5665_HPR_GAIN:
+       case RT5665_MONO_GAIN:
+       case RT5665_CAL_BST_CTRL:
+       case RT5665_CBJ_BST_CTRL:
+       case RT5665_IN1_IN2:
+       case RT5665_IN3_IN4:
+       case RT5665_INL1_INR1_VOL:
+       case RT5665_EJD_CTRL_1:
+       case RT5665_EJD_CTRL_2:
+       case RT5665_EJD_CTRL_3:
+       case RT5665_EJD_CTRL_4:
+       case RT5665_EJD_CTRL_5:
+       case RT5665_EJD_CTRL_6:
+       case RT5665_EJD_CTRL_7:
+       case RT5665_DAC2_CTRL:
+       case RT5665_DAC2_DIG_VOL:
+       case RT5665_DAC1_DIG_VOL:
+       case RT5665_DAC3_DIG_VOL:
+       case RT5665_DAC3_CTRL:
+       case RT5665_STO1_ADC_DIG_VOL:
+       case RT5665_MONO_ADC_DIG_VOL:
+       case RT5665_STO2_ADC_DIG_VOL:
+       case RT5665_STO1_ADC_BOOST:
+       case RT5665_MONO_ADC_BOOST:
+       case RT5665_STO2_ADC_BOOST:
+       case RT5665_HP_IMP_GAIN_1:
+       case RT5665_HP_IMP_GAIN_2:
+       case RT5665_STO1_ADC_MIXER:
+       case RT5665_MONO_ADC_MIXER:
+       case RT5665_STO2_ADC_MIXER:
+       case RT5665_AD_DA_MIXER:
+       case RT5665_STO1_DAC_MIXER:
+       case RT5665_MONO_DAC_MIXER:
+       case RT5665_STO2_DAC_MIXER:
+       case RT5665_A_DAC1_MUX:
+       case RT5665_A_DAC2_MUX:
+       case RT5665_DIG_INF2_DATA:
+       case RT5665_DIG_INF3_DATA:
+       case RT5665_PDM_OUT_CTRL:
+       case RT5665_PDM_DATA_CTRL_1:
+       case RT5665_PDM_DATA_CTRL_2:
+       case RT5665_PDM_DATA_CTRL_3:
+       case RT5665_PDM_DATA_CTRL_4:
+       case RT5665_REC1_GAIN:
+       case RT5665_REC1_L1_MIXER:
+       case RT5665_REC1_L2_MIXER:
+       case RT5665_REC1_R1_MIXER:
+       case RT5665_REC1_R2_MIXER:
+       case RT5665_REC2_GAIN:
+       case RT5665_REC2_L1_MIXER:
+       case RT5665_REC2_L2_MIXER:
+       case RT5665_REC2_R1_MIXER:
+       case RT5665_REC2_R2_MIXER:
+       case RT5665_CAL_REC:
+       case RT5665_ALC_BACK_GAIN:
+       case RT5665_MONOMIX_GAIN:
+       case RT5665_MONOMIX_IN_GAIN:
+       case RT5665_OUT_L_GAIN:
+       case RT5665_OUT_L_MIXER:
+       case RT5665_OUT_R_GAIN:
+       case RT5665_OUT_R_MIXER:
+       case RT5665_LOUT_MIXER:
+       case RT5665_PWR_DIG_1:
+       case RT5665_PWR_DIG_2:
+       case RT5665_PWR_ANLG_1:
+       case RT5665_PWR_ANLG_2:
+       case RT5665_PWR_ANLG_3:
+       case RT5665_PWR_MIXER:
+       case RT5665_PWR_VOL:
+       case RT5665_CLK_DET:
+       case RT5665_HPF_CTRL1:
+       case RT5665_DMIC_CTRL_1:
+       case RT5665_DMIC_CTRL_2:
+       case RT5665_I2S1_SDP:
+       case RT5665_I2S2_SDP:
+       case RT5665_I2S3_SDP:
+       case RT5665_ADDA_CLK_1:
+       case RT5665_ADDA_CLK_2:
+       case RT5665_I2S1_F_DIV_CTRL_1:
+       case RT5665_I2S1_F_DIV_CTRL_2:
+       case RT5665_TDM_CTRL_1:
+       case RT5665_TDM_CTRL_2:
+       case RT5665_TDM_CTRL_3:
+       case RT5665_TDM_CTRL_4:
+       case RT5665_TDM_CTRL_5:
+       case RT5665_TDM_CTRL_6:
+       case RT5665_TDM_CTRL_7:
+       case RT5665_TDM_CTRL_8:
+       case RT5665_GLB_CLK:
+       case RT5665_PLL_CTRL_1:
+       case RT5665_PLL_CTRL_2:
+       case RT5665_ASRC_1:
+       case RT5665_ASRC_2:
+       case RT5665_ASRC_3:
+       case RT5665_ASRC_4:
+       case RT5665_ASRC_5:
+       case RT5665_ASRC_6:
+       case RT5665_ASRC_7:
+       case RT5665_ASRC_8:
+       case RT5665_ASRC_9:
+       case RT5665_ASRC_10:
+       case RT5665_DEPOP_1:
+       case RT5665_DEPOP_2:
+       case RT5665_HP_CHARGE_PUMP_1:
+       case RT5665_HP_CHARGE_PUMP_2:
+       case RT5665_MICBIAS_1:
+       case RT5665_MICBIAS_2:
+       case RT5665_ASRC_12:
+       case RT5665_ASRC_13:
+       case RT5665_ASRC_14:
+       case RT5665_RC_CLK_CTRL:
+       case RT5665_I2S_M_CLK_CTRL_1:
+       case RT5665_I2S2_F_DIV_CTRL_1:
+       case RT5665_I2S2_F_DIV_CTRL_2:
+       case RT5665_I2S3_F_DIV_CTRL_1:
+       case RT5665_I2S3_F_DIV_CTRL_2:
+       case RT5665_EQ_CTRL_1:
+       case RT5665_EQ_CTRL_2:
+       case RT5665_IRQ_CTRL_1:
+       case RT5665_IRQ_CTRL_2:
+       case RT5665_IRQ_CTRL_3:
+       case RT5665_IRQ_CTRL_4:
+       case RT5665_IRQ_CTRL_5:
+       case RT5665_IRQ_CTRL_6:
+       case RT5665_INT_ST_1:
+       case RT5665_GPIO_CTRL_1:
+       case RT5665_GPIO_CTRL_2:
+       case RT5665_GPIO_CTRL_3:
+       case RT5665_GPIO_CTRL_4:
+       case RT5665_GPIO_STA:
+       case RT5665_HP_AMP_DET_CTRL_1:
+       case RT5665_HP_AMP_DET_CTRL_2:
+       case RT5665_MID_HP_AMP_DET:
+       case RT5665_LOW_HP_AMP_DET:
+       case RT5665_SV_ZCD_1:
+       case RT5665_SV_ZCD_2:
+       case RT5665_IL_CMD_1:
+       case RT5665_IL_CMD_2:
+       case RT5665_IL_CMD_3:
+       case RT5665_IL_CMD_4:
+       case RT5665_4BTN_IL_CMD_1:
+       case RT5665_4BTN_IL_CMD_2:
+       case RT5665_4BTN_IL_CMD_3:
+       case RT5665_PSV_IL_CMD_1:
+       case RT5665_ADC_STO1_HP_CTRL_1:
+       case RT5665_ADC_STO1_HP_CTRL_2:
+       case RT5665_ADC_MONO_HP_CTRL_1:
+       case RT5665_ADC_MONO_HP_CTRL_2:
+       case RT5665_ADC_STO2_HP_CTRL_1:
+       case RT5665_ADC_STO2_HP_CTRL_2:
+       case RT5665_AJD1_CTRL:
+       case RT5665_JD1_THD:
+       case RT5665_JD2_THD:
+       case RT5665_JD_CTRL_1:
+       case RT5665_JD_CTRL_2:
+       case RT5665_JD_CTRL_3:
+       case RT5665_DIG_MISC:
+       case RT5665_DUMMY_2:
+       case RT5665_DUMMY_3:
+       case RT5665_DAC_ADC_DIG_VOL1:
+       case RT5665_DAC_ADC_DIG_VOL2:
+       case RT5665_BIAS_CUR_CTRL_1:
+       case RT5665_BIAS_CUR_CTRL_2:
+       case RT5665_BIAS_CUR_CTRL_3:
+       case RT5665_BIAS_CUR_CTRL_4:
+       case RT5665_BIAS_CUR_CTRL_5:
+       case RT5665_BIAS_CUR_CTRL_6:
+       case RT5665_BIAS_CUR_CTRL_7:
+       case RT5665_BIAS_CUR_CTRL_8:
+       case RT5665_BIAS_CUR_CTRL_9:
+       case RT5665_BIAS_CUR_CTRL_10:
+       case RT5665_VREF_REC_OP_FB_CAP_CTRL:
+       case RT5665_CHARGE_PUMP_1:
+       case RT5665_DIG_IN_CTRL_1:
+       case RT5665_DIG_IN_CTRL_2:
+       case RT5665_PAD_DRIVING_CTRL:
+       case RT5665_SOFT_RAMP_DEPOP:
+       case RT5665_PLL:
+       case RT5665_CHOP_DAC:
+       case RT5665_CHOP_ADC:
+       case RT5665_CALIB_ADC_CTRL:
+       case RT5665_VOL_TEST:
+       case RT5665_TEST_MODE_CTRL_1:
+       case RT5665_TEST_MODE_CTRL_2:
+       case RT5665_TEST_MODE_CTRL_3:
+       case RT5665_TEST_MODE_CTRL_4:
+       case RT5665_BASSBACK_CTRL:
+       case RT5665_STO_NG2_CTRL_1:
+       case RT5665_STO_NG2_CTRL_2:
+       case RT5665_STO_NG2_CTRL_3:
+       case RT5665_STO_NG2_CTRL_4:
+       case RT5665_STO_NG2_CTRL_5:
+       case RT5665_STO_NG2_CTRL_6:
+       case RT5665_STO_NG2_CTRL_7:
+       case RT5665_STO_NG2_CTRL_8:
+       case RT5665_MONO_NG2_CTRL_1:
+       case RT5665_MONO_NG2_CTRL_2:
+       case RT5665_MONO_NG2_CTRL_3:
+       case RT5665_MONO_NG2_CTRL_4:
+       case RT5665_MONO_NG2_CTRL_5:
+       case RT5665_MONO_NG2_CTRL_6:
+       case RT5665_STO1_DAC_SIL_DET:
+       case RT5665_MONOL_DAC_SIL_DET:
+       case RT5665_MONOR_DAC_SIL_DET:
+       case RT5665_STO2_DAC_SIL_DET:
+       case RT5665_SIL_PSV_CTRL1:
+       case RT5665_SIL_PSV_CTRL2:
+       case RT5665_SIL_PSV_CTRL3:
+       case RT5665_SIL_PSV_CTRL4:
+       case RT5665_SIL_PSV_CTRL5:
+       case RT5665_SIL_PSV_CTRL6:
+       case RT5665_MONO_AMP_CALIB_CTRL_1:
+       case RT5665_MONO_AMP_CALIB_CTRL_2:
+       case RT5665_MONO_AMP_CALIB_CTRL_3:
+       case RT5665_MONO_AMP_CALIB_CTRL_4:
+       case RT5665_MONO_AMP_CALIB_CTRL_5:
+       case RT5665_MONO_AMP_CALIB_CTRL_6:
+       case RT5665_MONO_AMP_CALIB_CTRL_7:
+       case RT5665_MONO_AMP_CALIB_STA1:
+       case RT5665_MONO_AMP_CALIB_STA2:
+       case RT5665_MONO_AMP_CALIB_STA3:
+       case RT5665_MONO_AMP_CALIB_STA4:
+       case RT5665_MONO_AMP_CALIB_STA6:
+       case RT5665_HP_IMP_SENS_CTRL_01:
+       case RT5665_HP_IMP_SENS_CTRL_02:
+       case RT5665_HP_IMP_SENS_CTRL_03:
+       case RT5665_HP_IMP_SENS_CTRL_04:
+       case RT5665_HP_IMP_SENS_CTRL_05:
+       case RT5665_HP_IMP_SENS_CTRL_06:
+       case RT5665_HP_IMP_SENS_CTRL_07:
+       case RT5665_HP_IMP_SENS_CTRL_08:
+       case RT5665_HP_IMP_SENS_CTRL_09:
+       case RT5665_HP_IMP_SENS_CTRL_10:
+       case RT5665_HP_IMP_SENS_CTRL_11:
+       case RT5665_HP_IMP_SENS_CTRL_12:
+       case RT5665_HP_IMP_SENS_CTRL_13:
+       case RT5665_HP_IMP_SENS_CTRL_14:
+       case RT5665_HP_IMP_SENS_CTRL_15:
+       case RT5665_HP_IMP_SENS_CTRL_16:
+       case RT5665_HP_IMP_SENS_CTRL_17:
+       case RT5665_HP_IMP_SENS_CTRL_18:
+       case RT5665_HP_IMP_SENS_CTRL_19:
+       case RT5665_HP_IMP_SENS_CTRL_20:
+       case RT5665_HP_IMP_SENS_CTRL_21:
+       case RT5665_HP_IMP_SENS_CTRL_22:
+       case RT5665_HP_IMP_SENS_CTRL_23:
+       case RT5665_HP_IMP_SENS_CTRL_24:
+       case RT5665_HP_IMP_SENS_CTRL_25:
+       case RT5665_HP_IMP_SENS_CTRL_26:
+       case RT5665_HP_IMP_SENS_CTRL_27:
+       case RT5665_HP_IMP_SENS_CTRL_28:
+       case RT5665_HP_IMP_SENS_CTRL_29:
+       case RT5665_HP_IMP_SENS_CTRL_30:
+       case RT5665_HP_IMP_SENS_CTRL_31:
+       case RT5665_HP_IMP_SENS_CTRL_32:
+       case RT5665_HP_IMP_SENS_CTRL_33:
+       case RT5665_HP_IMP_SENS_CTRL_34:
+       case RT5665_HP_LOGIC_CTRL_1:
+       case RT5665_HP_LOGIC_CTRL_2:
+       case RT5665_HP_LOGIC_CTRL_3:
+       case RT5665_HP_CALIB_CTRL_1:
+       case RT5665_HP_CALIB_CTRL_2:
+       case RT5665_HP_CALIB_CTRL_3:
+       case RT5665_HP_CALIB_CTRL_4:
+       case RT5665_HP_CALIB_CTRL_5:
+       case RT5665_HP_CALIB_CTRL_6:
+       case RT5665_HP_CALIB_CTRL_7:
+       case RT5665_HP_CALIB_CTRL_9:
+       case RT5665_HP_CALIB_CTRL_10:
+       case RT5665_HP_CALIB_CTRL_11:
+       case RT5665_HP_CALIB_STA_1:
+       case RT5665_HP_CALIB_STA_2:
+       case RT5665_HP_CALIB_STA_3:
+       case RT5665_HP_CALIB_STA_4:
+       case RT5665_HP_CALIB_STA_5:
+       case RT5665_HP_CALIB_STA_6:
+       case RT5665_HP_CALIB_STA_7:
+       case RT5665_HP_CALIB_STA_8:
+       case RT5665_HP_CALIB_STA_9:
+       case RT5665_HP_CALIB_STA_10:
+       case RT5665_HP_CALIB_STA_11:
+       case RT5665_PGM_TAB_CTRL1:
+       case RT5665_PGM_TAB_CTRL2:
+       case RT5665_PGM_TAB_CTRL3:
+       case RT5665_PGM_TAB_CTRL4:
+       case RT5665_PGM_TAB_CTRL5:
+       case RT5665_PGM_TAB_CTRL6:
+       case RT5665_PGM_TAB_CTRL7:
+       case RT5665_PGM_TAB_CTRL8:
+       case RT5665_PGM_TAB_CTRL9:
+       case RT5665_SAR_IL_CMD_1:
+       case RT5665_SAR_IL_CMD_2:
+       case RT5665_SAR_IL_CMD_3:
+       case RT5665_SAR_IL_CMD_4:
+       case RT5665_SAR_IL_CMD_5:
+       case RT5665_SAR_IL_CMD_6:
+       case RT5665_SAR_IL_CMD_7:
+       case RT5665_SAR_IL_CMD_8:
+       case RT5665_SAR_IL_CMD_9:
+       case RT5665_SAR_IL_CMD_10:
+       case RT5665_SAR_IL_CMD_11:
+       case RT5665_SAR_IL_CMD_12:
+       case RT5665_DRC1_CTRL_0:
+       case RT5665_DRC1_CTRL_1:
+       case RT5665_DRC1_CTRL_2:
+       case RT5665_DRC1_CTRL_3:
+       case RT5665_DRC1_CTRL_4:
+       case RT5665_DRC1_CTRL_5:
+       case RT5665_DRC1_CTRL_6:
+       case RT5665_DRC1_HARD_LMT_CTRL_1:
+       case RT5665_DRC1_HARD_LMT_CTRL_2:
+       case RT5665_DRC1_PRIV_1:
+       case RT5665_DRC1_PRIV_2:
+       case RT5665_DRC1_PRIV_3:
+       case RT5665_DRC1_PRIV_4:
+       case RT5665_DRC1_PRIV_5:
+       case RT5665_DRC1_PRIV_6:
+       case RT5665_DRC1_PRIV_7:
+       case RT5665_DRC1_PRIV_8:
+       case RT5665_ALC_PGA_CTRL_1:
+       case RT5665_ALC_PGA_CTRL_2:
+       case RT5665_ALC_PGA_CTRL_3:
+       case RT5665_ALC_PGA_CTRL_4:
+       case RT5665_ALC_PGA_CTRL_5:
+       case RT5665_ALC_PGA_CTRL_6:
+       case RT5665_ALC_PGA_CTRL_7:
+       case RT5665_ALC_PGA_CTRL_8:
+       case RT5665_ALC_PGA_STA_1:
+       case RT5665_ALC_PGA_STA_2:
+       case RT5665_ALC_PGA_STA_3:
+       case RT5665_EQ_AUTO_RCV_CTRL1:
+       case RT5665_EQ_AUTO_RCV_CTRL2:
+       case RT5665_EQ_AUTO_RCV_CTRL3:
+       case RT5665_EQ_AUTO_RCV_CTRL4:
+       case RT5665_EQ_AUTO_RCV_CTRL5:
+       case RT5665_EQ_AUTO_RCV_CTRL6:
+       case RT5665_EQ_AUTO_RCV_CTRL7:
+       case RT5665_EQ_AUTO_RCV_CTRL8:
+       case RT5665_EQ_AUTO_RCV_CTRL9:
+       case RT5665_EQ_AUTO_RCV_CTRL10:
+       case RT5665_EQ_AUTO_RCV_CTRL11:
+       case RT5665_EQ_AUTO_RCV_CTRL12:
+       case RT5665_EQ_AUTO_RCV_CTRL13:
+       case RT5665_ADC_L_EQ_LPF1_A1:
+       case RT5665_R_EQ_LPF1_A1:
+       case RT5665_L_EQ_LPF1_H0:
+       case RT5665_R_EQ_LPF1_H0:
+       case RT5665_L_EQ_BPF1_A1:
+       case RT5665_R_EQ_BPF1_A1:
+       case RT5665_L_EQ_BPF1_A2:
+       case RT5665_R_EQ_BPF1_A2:
+       case RT5665_L_EQ_BPF1_H0:
+       case RT5665_R_EQ_BPF1_H0:
+       case RT5665_L_EQ_BPF2_A1:
+       case RT5665_R_EQ_BPF2_A1:
+       case RT5665_L_EQ_BPF2_A2:
+       case RT5665_R_EQ_BPF2_A2:
+       case RT5665_L_EQ_BPF2_H0:
+       case RT5665_R_EQ_BPF2_H0:
+       case RT5665_L_EQ_BPF3_A1:
+       case RT5665_R_EQ_BPF3_A1:
+       case RT5665_L_EQ_BPF3_A2:
+       case RT5665_R_EQ_BPF3_A2:
+       case RT5665_L_EQ_BPF3_H0:
+       case RT5665_R_EQ_BPF3_H0:
+       case RT5665_L_EQ_BPF4_A1:
+       case RT5665_R_EQ_BPF4_A1:
+       case RT5665_L_EQ_BPF4_A2:
+       case RT5665_R_EQ_BPF4_A2:
+       case RT5665_L_EQ_BPF4_H0:
+       case RT5665_R_EQ_BPF4_H0:
+       case RT5665_L_EQ_HPF1_A1:
+       case RT5665_R_EQ_HPF1_A1:
+       case RT5665_L_EQ_HPF1_H0:
+       case RT5665_R_EQ_HPF1_H0:
+       case RT5665_L_EQ_PRE_VOL:
+       case RT5665_R_EQ_PRE_VOL:
+       case RT5665_L_EQ_POST_VOL:
+       case RT5665_R_EQ_POST_VOL:
+       case RT5665_SCAN_MODE_CTRL:
+       case RT5665_I2C_MODE:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mono_vol_tlv, -1400, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+       6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+       7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+       8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5665_data_select[] = {
+       "L/R", "R/L", "L/L", "R/R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT01_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT23_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT45_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT67_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_01_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT01_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_23_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT23_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_45_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT45_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_67_adc_enum,
+       RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT67_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_dac_enum,
+       RT5665_DIG_INF2_DATA, RT5665_IF2_1_DAC_SEL_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_adc_enum,
+       RT5665_DIG_INF2_DATA, RT5665_IF2_1_ADC_SEL_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_dac_enum,
+       RT5665_DIG_INF2_DATA, RT5665_IF2_2_DAC_SEL_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_adc_enum,
+       RT5665_DIG_INF2_DATA, RT5665_IF2_2_ADC_SEL_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if3_dac_enum,
+       RT5665_DIG_INF3_DATA, RT5665_IF3_DAC_SEL_SFT, rt5665_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5665_if3_adc_enum,
+       RT5665_DIG_INF3_DATA, RT5665_IF3_ADC_SEL_SFT, rt5665_data_select);
+
+static const struct snd_kcontrol_new rt5665_if1_1_01_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_1 01 ADC Swap Mux", rt5665_if1_1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_1_23_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_1 23 ADC Swap Mux", rt5665_if1_1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_1_45_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_1 45 ADC Swap Mux", rt5665_if1_1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_1_67_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_1 67 ADC Swap Mux", rt5665_if1_1_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_01_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_2 01 ADC Swap Mux", rt5665_if1_2_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_23_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_2 23 ADC1 Swap Mux", rt5665_if1_2_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_45_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_2 45 ADC1 Swap Mux", rt5665_if1_2_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if1_2_67_adc_swap_mux =
+       SOC_DAPM_ENUM("IF1_2 67 ADC1 Swap Mux", rt5665_if1_2_67_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_1_dac_swap_mux =
+       SOC_DAPM_ENUM("IF2_1 DAC Swap Source", rt5665_if2_1_dac_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_1_adc_swap_mux =
+       SOC_DAPM_ENUM("IF2_1 ADC Swap Source", rt5665_if2_1_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_2_dac_swap_mux =
+       SOC_DAPM_ENUM("IF2_2 DAC Swap Source", rt5665_if2_2_dac_enum);
+
+static const struct snd_kcontrol_new rt5665_if2_2_adc_swap_mux =
+       SOC_DAPM_ENUM("IF2_2 ADC Swap Source", rt5665_if2_2_adc_enum);
+
+static const struct snd_kcontrol_new rt5665_if3_dac_swap_mux =
+       SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5665_if3_dac_enum);
+
+static const struct snd_kcontrol_new rt5665_if3_adc_swap_mux =
+       SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5665_if3_adc_enum);
+
+static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+       if (snd_soc_read(codec, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) {
+               snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+               snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+       }
+
+       return ret;
+}
+
+static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       int ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+       if (snd_soc_read(codec, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) {
+               snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+               snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+       }
+
+       return ret;
+}
+
+/**
+ * rt5665_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5665 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec,
+               unsigned int filter_mask, unsigned int clk_src)
+{
+       unsigned int asrc2_mask = 0;
+       unsigned int asrc2_value = 0;
+       unsigned int asrc3_mask = 0;
+       unsigned int asrc3_value = 0;
+
+       switch (clk_src) {
+       case RT5665_CLK_SEL_SYS:
+       case RT5665_CLK_SEL_I2S1_ASRC:
+       case RT5665_CLK_SEL_I2S2_ASRC:
+       case RT5665_CLK_SEL_I2S3_ASRC:
+       case RT5665_CLK_SEL_SYS2:
+       case RT5665_CLK_SEL_SYS3:
+       case RT5665_CLK_SEL_SYS4:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (filter_mask & RT5665_DA_STEREO1_FILTER) {
+               asrc2_mask |= RT5665_DA_STO1_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5665_DA_STO1_CLK_SEL_MASK)
+                       | (clk_src << RT5665_DA_STO1_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5665_DA_STEREO2_FILTER) {
+               asrc2_mask |= RT5665_DA_STO2_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5665_DA_STO2_CLK_SEL_MASK)
+                       | (clk_src << RT5665_DA_STO2_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5665_DA_MONO_L_FILTER) {
+               asrc2_mask |= RT5665_DA_MONOL_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5665_DA_MONOL_CLK_SEL_MASK)
+                       | (clk_src << RT5665_DA_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5665_DA_MONO_R_FILTER) {
+               asrc2_mask |= RT5665_DA_MONOR_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5665_DA_MONOR_CLK_SEL_MASK)
+                       | (clk_src << RT5665_DA_MONOR_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5665_AD_STEREO1_FILTER) {
+               asrc3_mask |= RT5665_AD_STO1_CLK_SEL_MASK;
+               asrc3_value = (asrc2_value & ~RT5665_AD_STO1_CLK_SEL_MASK)
+                       | (clk_src << RT5665_AD_STO1_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5665_AD_STEREO2_FILTER) {
+               asrc3_mask |= RT5665_AD_STO2_CLK_SEL_MASK;
+               asrc3_value = (asrc2_value & ~RT5665_AD_STO2_CLK_SEL_MASK)
+                       | (clk_src << RT5665_AD_STO2_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5665_AD_MONO_L_FILTER) {
+               asrc3_mask |= RT5665_AD_MONOL_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5665_AD_MONOL_CLK_SEL_MASK)
+                       | (clk_src << RT5665_AD_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5665_AD_MONO_R_FILTER)  {
+               asrc3_mask |= RT5665_AD_MONOR_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5665_AD_MONOR_CLK_SEL_MASK)
+                       | (clk_src << RT5665_AD_MONOR_CLK_SEL_SFT);
+       }
+
+       if (asrc2_mask)
+               snd_soc_update_bits(codec, RT5665_ASRC_2,
+                       asrc2_mask, asrc2_value);
+
+       if (asrc3_mask)
+               snd_soc_update_bits(codec, RT5665_ASRC_3,
+                       asrc3_mask, asrc3_value);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5665_sel_asrc_clk_src);
+
+static int rt5665_button_detect(struct snd_soc_codec *codec)
+{
+       int btn_type, val;
+
+       val = snd_soc_read(codec, RT5665_4BTN_IL_CMD_1);
+       btn_type = val & 0xfff0;
+       snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, val);
+
+       return btn_type;
+}
+
+static void rt5665_enable_push_button_irq(struct snd_soc_codec *codec,
+       bool enable)
+{
+       if (enable) {
+               snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x000b);
+               snd_soc_write(codec, RT5665_IL_CMD_1, 0x0048);
+               snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2,
+                               RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK,
+                               RT5665_4BTN_IL_EN | RT5665_4BTN_IL_NOR);
+               snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3,
+                               RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_EN);
+       } else {
+               snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3,
+                               RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_DIS);
+               snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2,
+                               RT5665_4BTN_IL_MASK, RT5665_4BTN_IL_DIS);
+               snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2,
+                               RT5665_4BTN_IL_RST_MASK, RT5665_4BTN_IL_RST);
+       }
+}
+
+/**
+ * rt5665_headset_detect - Detect headset.
+ * @codec: SoC audio codec device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       unsigned int sar_hs_type, val;
+
+       if (jack_insert) {
+               snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+               snd_soc_dapm_sync(dapm);
+
+               regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100,
+                       0x100);
+
+               regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val);
+               if (val & 0x4) {
+                       regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
+                               0x100, 0);
+
+                       regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val);
+                       while (val & 0x4) {
+                               usleep_range(10000, 15000);
+                               regmap_read(rt5665->regmap, RT5665_GPIO_STA,
+                                       &val);
+                       }
+               }
+
+               regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
+                       0x180, 0x180);
+               regmap_write(rt5665->regmap, RT5665_EJD_CTRL_3, 0x3424);
+               regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0xa291);
+
+               rt5665->sar_adc_value = snd_soc_read(rt5665->codec,
+                       RT5665_SAR_IL_CMD_4) & 0x7ff;
+
+               sar_hs_type = rt5665->pdata.sar_hs_type ?
+                       rt5665->pdata.sar_hs_type : 729;
+
+               if (rt5665->sar_adc_value > sar_hs_type) {
+                       rt5665->jack_type = SND_JACK_HEADSET;
+                       rt5665_enable_push_button_irq(codec, true);
+                       } else {
+                       rt5665->jack_type = SND_JACK_HEADPHONE;
+                       regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1,
+                               0x2291);
+                       regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2,
+                               0x100, 0);
+                       snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+                       snd_soc_dapm_sync(dapm);
+               }
+       } else {
+               regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0x2291);
+               regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, 0);
+               snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
+               snd_soc_dapm_sync(dapm);
+               if (rt5665->jack_type == SND_JACK_HEADSET)
+                       rt5665_enable_push_button_irq(codec, false);
+               rt5665->jack_type = 0;
+       }
+
+       dev_dbg(codec->dev, "jack_type = %d\n", rt5665->jack_type);
+       return rt5665->jack_type;
+}
+
+static irqreturn_t rt5665_irq(int irq, void *data)
+{
+       struct rt5665_priv *rt5665 = data;
+
+       mod_delayed_work(system_power_efficient_wq,
+                          &rt5665->jack_detect_work, msecs_to_jiffies(250));
+
+       return IRQ_HANDLED;
+}
+
+static void rt5665_jd_check_handler(struct work_struct *work)
+{
+       struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv,
+               calibrate_work.work);
+
+       if (snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010) {
+               /* jack out */
+               rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0);
+
+               snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type,
+                               SND_JACK_HEADSET |
+                               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                               SND_JACK_BTN_2 | SND_JACK_BTN_3);
+       } else {
+               schedule_delayed_work(&rt5665->jd_check_work, 500);
+       }
+}
+
+int rt5665_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *hs_jack)
+{
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+
+       switch (rt5665->pdata.jd_src) {
+       case RT5665_JD1:
+               regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+                       RT5665_GP1_PIN_MASK, RT5665_GP1_PIN_IRQ);
+               regmap_update_bits(rt5665->regmap, RT5665_RC_CLK_CTRL,
+                               0xc000, 0xc000);
+               regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_2,
+                       RT5665_PWR_JD1, RT5665_PWR_JD1);
+               regmap_update_bits(rt5665->regmap, RT5665_IRQ_CTRL_1, 0x8, 0x8);
+               break;
+
+       case RT5665_JD_NULL:
+               break;
+
+       default:
+               dev_warn(codec->dev, "Wrong JD source\n");
+               break;
+       }
+
+       rt5665->hs_jack = hs_jack;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5665_set_jack_detect);
+
+static void rt5665_jack_detect_handler(struct work_struct *work)
+{
+       struct rt5665_priv *rt5665 =
+               container_of(work, struct rt5665_priv, jack_detect_work.work);
+       int val, btn_type;
+
+       while (!rt5665->codec) {
+               pr_debug("%s codec = null\n", __func__);
+               usleep_range(10000, 15000);
+       }
+
+       while (!rt5665->codec->component.card->instantiated) {
+               pr_debug("%s\n", __func__);
+               usleep_range(10000, 15000);
+       }
+
+       mutex_lock(&rt5665->calibrate_mutex);
+
+       val = snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010;
+       if (!val) {
+               /* jack in */
+               if (rt5665->jack_type == 0) {
+                       /* jack was out, report jack type */
+                       rt5665->jack_type =
+                               rt5665_headset_detect(rt5665->codec, 1);
+               } else {
+                       /* jack is already in, report button event */
+                       rt5665->jack_type = SND_JACK_HEADSET;
+                       btn_type = rt5665_button_detect(rt5665->codec);
+                       /**
+                        * rt5665 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:
+                               rt5665->jack_type |= SND_JACK_BTN_0;
+                               break;
+                       case 0x1000:
+                       case 0x0800:
+                       case 0x0400:
+                               rt5665->jack_type |= SND_JACK_BTN_1;
+                               break;
+                       case 0x0200:
+                       case 0x0100:
+                       case 0x0080:
+                               rt5665->jack_type |= SND_JACK_BTN_2;
+                               break;
+                       case 0x0040:
+                       case 0x0020:
+                       case 0x0010:
+                               rt5665->jack_type |= SND_JACK_BTN_3;
+                               break;
+                       case 0x0000: /* unpressed */
+                               break;
+                       default:
+                               btn_type = 0;
+                               dev_err(rt5665->codec->dev,
+                                       "Unexpected button code 0x%04x\n",
+                                       btn_type);
+                               break;
+                       }
+               }
+       } else {
+               /* jack out */
+               rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0);
+       }
+
+       snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type,
+                       SND_JACK_HEADSET |
+                           SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                           SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+       if (rt5665->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+               SND_JACK_BTN_2 | SND_JACK_BTN_3))
+               schedule_delayed_work(&rt5665->jd_check_work, 0);
+       else
+               cancel_delayed_work_sync(&rt5665->jd_check_work);
+
+       mutex_unlock(&rt5665->calibrate_mutex);
+}
+
+static const struct snd_kcontrol_new rt5665_snd_controls[] = {
+       /* Headphone Output Volume */
+       SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN,
+               RT5665_HPR_GAIN, RT5665_G_HP_SFT, 15, 1, snd_soc_get_volsw,
+               rt5665_hp_vol_put, hp_vol_tlv),
+
+       /* Mono Output Volume */
+       SOC_SINGLE_EXT_TLV("Mono Playback Volume", RT5665_MONO_GAIN,
+               RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw,
+               rt5665_mono_vol_put, mono_vol_tlv),
+
+       /* Output Volume */
+       SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT,
+               RT5665_R_VOL_SFT, 39, 1, out_vol_tlv),
+
+       /* DAC Digital Volume */
+       SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5665_DAC1_DIG_VOL,
+               RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv),
+       SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5665_DAC2_DIG_VOL,
+               RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv),
+       SOC_DOUBLE("DAC2 Playback Switch", RT5665_DAC2_CTRL,
+               RT5665_M_DAC2_L_VOL_SFT, RT5665_M_DAC2_R_VOL_SFT, 1, 1),
+
+       /* IN1/IN2/IN3/IN4 Volume */
+       SOC_SINGLE_TLV("IN1 Boost Volume", RT5665_IN1_IN2,
+               RT5665_BST1_SFT, 69, 0, in_bst_tlv),
+       SOC_SINGLE_TLV("IN2 Boost Volume", RT5665_IN1_IN2,
+               RT5665_BST2_SFT, 69, 0, in_bst_tlv),
+       SOC_SINGLE_TLV("IN3 Boost Volume", RT5665_IN3_IN4,
+               RT5665_BST3_SFT, 69, 0, in_bst_tlv),
+       SOC_SINGLE_TLV("IN4 Boost Volume", RT5665_IN3_IN4,
+               RT5665_BST4_SFT, 69, 0, in_bst_tlv),
+       SOC_SINGLE_TLV("CBJ Boost Volume", RT5665_CBJ_BST_CTRL,
+               RT5665_BST_CBJ_SFT, 8, 0, bst_tlv),
+
+       /* INL/INR Volume Control */
+       SOC_DOUBLE_TLV("IN Capture Volume", RT5665_INL1_INR1_VOL,
+               RT5665_INL_VOL_SFT, RT5665_INR_VOL_SFT, 31, 1, in_vol_tlv),
+
+       /* ADC Digital Volume Control */
+       SOC_DOUBLE("STO1 ADC Capture Switch", RT5665_STO1_ADC_DIG_VOL,
+               RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5665_STO1_ADC_DIG_VOL,
+               RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv),
+       SOC_DOUBLE("Mono ADC Capture Switch", RT5665_MONO_ADC_DIG_VOL,
+               RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5665_MONO_ADC_DIG_VOL,
+               RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv),
+       SOC_DOUBLE("STO2 ADC Capture Switch", RT5665_STO2_ADC_DIG_VOL,
+               RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5665_STO2_ADC_DIG_VOL,
+               RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+       /* ADC Boost Volume Control */
+       SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5665_STO1_ADC_BOOST,
+               RT5665_STO1_ADC_L_BST_SFT, RT5665_STO1_ADC_R_BST_SFT,
+               3, 0, adc_bst_tlv),
+
+       SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5665_MONO_ADC_BOOST,
+               RT5665_MONO_ADC_L_BST_SFT, RT5665_MONO_ADC_R_BST_SFT,
+               3, 0, adc_bst_tlv),
+
+       SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST,
+               RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT,
+               3, 0, adc_bst_tlv),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+       int pd, idx = -EINVAL;
+
+       pd = rl6231_get_pre_div(rt5665->regmap,
+               RT5665_ADDA_CLK_1, RT5665_I2S_PD1_SFT);
+       idx = rl6231_calc_dmic_clk(rt5665->sysclk / pd);
+
+       if (idx < 0)
+               dev_err(codec->dev, "Failed to set DMIC clock\n");
+       else {
+               snd_soc_update_bits(codec, RT5665_DMIC_CTRL_1,
+                       RT5665_DMIC_CLK_MASK, idx << RT5665_DMIC_CLK_SFT);
+       }
+       return idx;
+}
+
+static int rt5665_charge_pump_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1,
+                       RT5665_PM_HP_MASK | RT5665_OSW_L_MASK,
+                       RT5665_PM_HP_HV | RT5665_OSW_L_EN);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1,
+                       RT5665_PM_HP_MASK | RT5665_OSW_L_MASK,
+                       RT5665_PM_HP_LV | RT5665_OSW_L_DIS);
+               break;
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int val;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       val = snd_soc_read(codec, RT5665_GLB_CLK);
+       val &= RT5665_SCLK_SRC_MASK;
+       if (val == RT5665_SCLK_SRC_PLL1)
+               return 1;
+       else
+               return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int reg, shift, val;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (w->shift) {
+       case RT5665_ADC_MONO_R_ASRC_SFT:
+               reg = RT5665_ASRC_3;
+               shift = RT5665_AD_MONOR_CLK_SEL_SFT;
+               break;
+       case RT5665_ADC_MONO_L_ASRC_SFT:
+               reg = RT5665_ASRC_3;
+               shift = RT5665_AD_MONOL_CLK_SEL_SFT;
+               break;
+       case RT5665_ADC_STO1_ASRC_SFT:
+               reg = RT5665_ASRC_3;
+               shift = RT5665_AD_STO1_CLK_SEL_SFT;
+               break;
+       case RT5665_ADC_STO2_ASRC_SFT:
+               reg = RT5665_ASRC_3;
+               shift = RT5665_AD_STO2_CLK_SEL_SFT;
+               break;
+       case RT5665_DAC_MONO_R_ASRC_SFT:
+               reg = RT5665_ASRC_2;
+               shift = RT5665_DA_MONOR_CLK_SEL_SFT;
+               break;
+       case RT5665_DAC_MONO_L_ASRC_SFT:
+               reg = RT5665_ASRC_2;
+               shift = RT5665_DA_MONOL_CLK_SEL_SFT;
+               break;
+       case RT5665_DAC_STO1_ASRC_SFT:
+               reg = RT5665_ASRC_2;
+               shift = RT5665_DA_STO1_CLK_SEL_SFT;
+               break;
+       case RT5665_DAC_STO2_ASRC_SFT:
+               reg = RT5665_ASRC_2;
+               shift = RT5665_DA_STO2_CLK_SEL_SFT;
+               break;
+       default:
+               return 0;
+       }
+
+       val = (snd_soc_read(codec, reg) >> shift) & 0xf;
+       switch (val) {
+       case RT5665_CLK_SEL_I2S1_ASRC:
+       case RT5665_CLK_SEL_I2S2_ASRC:
+       case RT5665_CLK_SEL_I2S3_ASRC:
+               /* I2S_Pre_Div1 should be 1 in asrc mode */
+               snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+                       RT5665_I2S_PD1_MASK, RT5665_I2S_PD1_2);
+               return 1;
+       default:
+               return 0;
+       }
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5665_sto1_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER,
+                       RT5665_M_STO1_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER,
+                       RT5665_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto1_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER,
+                       RT5665_M_STO1_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER,
+                       RT5665_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER,
+                       RT5665_M_STO2_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER,
+                       RT5665_M_STO2_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER,
+                       RT5665_M_STO2_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER,
+                       RT5665_M_STO2_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER,
+                       RT5665_M_MONO_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER,
+                       RT5665_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER,
+                       RT5665_M_MONO_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER,
+                       RT5665_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER,
+                       RT5665_M_ADCMIX_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER,
+                       RT5665_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER,
+                       RT5665_M_ADCMIX_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER,
+                       RT5665_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto1_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_L1_STO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_R1_STO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_L2_STO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_R2_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto1_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_L1_STO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_R1_STO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_L2_STO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER,
+                       RT5665_M_DAC_R2_STO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO2_DAC_MIXER,
+                       RT5665_M_DAC_L1_STO2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO2_DAC_MIXER,
+                       RT5665_M_DAC_L2_STO2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L3 Switch", RT5665_STO2_DAC_MIXER,
+                       RT5665_M_DAC_L3_STO2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_sto2_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO2_DAC_MIXER,
+                       RT5665_M_DAC_R1_STO2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO2_DAC_MIXER,
+                       RT5665_M_DAC_R2_STO2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R3 Switch", RT5665_STO2_DAC_MIXER,
+                       RT5665_M_DAC_R3_STO2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_L1_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_R1_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_L2_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_L1_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_R1_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_L2_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER,
+                       RT5665_M_DAC_R2_MONO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5665_rec1_l_mix[] = {
+       SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC1_L2_MIXER,
+                       RT5665_M_CBJ_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5665_REC1_L2_MIXER,
+                       RT5665_M_INL_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_L2_MIXER,
+                       RT5665_M_INR_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_L2_MIXER,
+                       RT5665_M_BST4_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_L2_MIXER,
+                       RT5665_M_BST3_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_L2_MIXER,
+                       RT5665_M_BST2_RM1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_L2_MIXER,
+                       RT5665_M_BST1_RM1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_rec1_r_mix[] = {
+       SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC1_R2_MIXER,
+                       RT5665_M_AEC_REF_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_R2_MIXER,
+                       RT5665_M_INR_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_R2_MIXER,
+                       RT5665_M_BST4_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_R2_MIXER,
+                       RT5665_M_BST3_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_R2_MIXER,
+                       RT5665_M_BST2_RM1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_R2_MIXER,
+                       RT5665_M_BST1_RM1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_rec2_l_mix[] = {
+       SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_L2_MIXER,
+                       RT5665_M_INL_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_L2_MIXER,
+                       RT5665_M_INR_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC2_L2_MIXER,
+                       RT5665_M_CBJ_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_L2_MIXER,
+                       RT5665_M_BST4_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_L2_MIXER,
+                       RT5665_M_BST3_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_L2_MIXER,
+                       RT5665_M_BST2_RM2_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_L2_MIXER,
+                       RT5665_M_BST1_RM2_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_rec2_r_mix[] = {
+       SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC2_R2_MIXER,
+                       RT5665_M_MONOVOL_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_R2_MIXER,
+                       RT5665_M_INL_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_R2_MIXER,
+                       RT5665_M_INR_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_R2_MIXER,
+                       RT5665_M_BST4_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_R2_MIXER,
+                       RT5665_M_BST3_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_R2_MIXER,
+                       RT5665_M_BST2_RM2_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_R2_MIXER,
+                       RT5665_M_BST1_RM2_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_monovol_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN,
+                       RT5665_M_DAC_L2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("RECMIX2L Switch", RT5665_MONOMIX_IN_GAIN,
+                       RT5665_M_RECMIC2L_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5665_MONOMIX_IN_GAIN,
+                       RT5665_M_BST1_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5665_MONOMIX_IN_GAIN,
+                       RT5665_M_BST2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5665_MONOMIX_IN_GAIN,
+                       RT5665_M_BST3_MM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_out_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_OUT_L_MIXER,
+                       RT5665_M_DAC_L2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5665_OUT_L_MIXER,
+                       RT5665_M_IN_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5665_OUT_L_MIXER,
+                       RT5665_M_BST1_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_L_MIXER,
+                       RT5665_M_BST2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_L_MIXER,
+                       RT5665_M_BST3_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_out_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_OUT_R_MIXER,
+                       RT5665_M_DAC_R2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5665_OUT_R_MIXER,
+                       RT5665_M_IN_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_R_MIXER,
+                       RT5665_M_BST2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_R_MIXER,
+                       RT5665_M_BST3_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST4 Switch", RT5665_OUT_R_MIXER,
+                       RT5665_M_BST4_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_mono_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN,
+                       RT5665_M_DAC_L2_MA_SFT, 1, 1),
+       SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_MONOMIX_IN_GAIN,
+                       RT5665_M_MONOVOL_MA_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_lout_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_LOUT_MIXER,
+                       RT5665_M_DAC_L2_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5665_LOUT_MIXER,
+                       RT5665_M_OV_L_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5665_lout_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_LOUT_MIXER,
+                       RT5665_M_DAC_R2_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5665_LOUT_MIXER,
+                       RT5665_M_OV_R_LM_SFT, 1, 1),
+};
+
+/*DAC L2, DAC R2*/
+/*MX-17 [6:4], MX-17 [2:0]*/
+static const char * const rt5665_dac2_src[] = {
+       "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "Mono ADC MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dac_l2_enum, RT5665_DAC2_CTRL,
+       RT5665_DAC_L2_SEL_SFT, rt5665_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_dac_l2_mux =
+       SOC_DAPM_ENUM("Digital DAC L2 Source", rt5665_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dac_r2_enum, RT5665_DAC2_CTRL,
+       RT5665_DAC_R2_SEL_SFT, rt5665_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_dac_r2_mux =
+       SOC_DAPM_ENUM("Digital DAC R2 Source", rt5665_dac_r2_enum);
+
+/*DAC L3, DAC R3*/
+/*MX-1B [6:4], MX-1B [2:0]*/
+static const char * const rt5665_dac3_src[] = {
+       "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "STO2 ADC MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dac_l3_enum, RT5665_DAC3_CTRL,
+       RT5665_DAC_L3_SEL_SFT, rt5665_dac3_src);
+
+static const struct snd_kcontrol_new rt5665_dac_l3_mux =
+       SOC_DAPM_ENUM("Digital DAC L3 Source", rt5665_dac_l3_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dac_r3_enum, RT5665_DAC3_CTRL,
+       RT5665_DAC_R3_SEL_SFT, rt5665_dac3_src);
+
+static const struct snd_kcontrol_new rt5665_dac_r3_mux =
+       SOC_DAPM_ENUM("Digital DAC R3 Source", rt5665_dac_r3_enum);
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] [5] */
+static const char * const rt5665_sto1_adc1_src[] = {
+       "DD Mux", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_adc1l_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_ADC1L_SRC_SFT, rt5665_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc1l_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_adc1r_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_ADC1R_SRC_SFT, rt5665_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc1r_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1r_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [11:10] [3:2] */
+static const char * const rt5665_sto1_adc_src[] = {
+       "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_adcl_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_ADCL_SRC_SFT, rt5665_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adcl_mux =
+       SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5665_sto1_adcl_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_adcr_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_ADCR_SRC_SFT, rt5665_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adcr_mux =
+       SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5665_sto1_adcr_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [12] [4] */
+static const char * const rt5665_sto1_adc2_src[] = {
+       "DAC MIX", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_adc2l_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_ADC2L_SRC_SFT, rt5665_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc2l_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5665_sto1_adc2l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_adc2r_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_ADC2R_SRC_SFT, rt5665_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_adc2r_mux =
+       SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5665_sto1_adc2r_enum);
+
+/* STO1 DMIC Source */
+/* MX-26 [8] */
+static const char * const rt5665_sto1_dmic_src[] = {
+       "DMIC1", "DMIC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_dmic_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_DMIC_SRC_SFT, rt5665_sto1_dmic_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_dmic_mux =
+       SOC_DAPM_ENUM("Stereo1 DMIC Mux", rt5665_sto1_dmic_enum);
+
+/* MX-26 [9] */
+static const char * const rt5665_sto1_dd_l_src[] = {
+       "STO2 DAC", "MONO DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_dd_l_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_DD_L_SRC_SFT, rt5665_sto1_dd_l_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_dd_l_mux =
+       SOC_DAPM_ENUM("Stereo1 DD L Source", rt5665_sto1_dd_l_enum);
+
+/* MX-26 [1:0] */
+static const char * const rt5665_sto1_dd_r_src[] = {
+       "STO2 DAC", "MONO DAC", "AEC REF"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto1_dd_r_enum, RT5665_STO1_ADC_MIXER,
+       RT5665_STO1_DD_R_SRC_SFT, rt5665_sto1_dd_r_src);
+
+static const struct snd_kcontrol_new rt5665_sto1_dd_r_mux =
+       SOC_DAPM_ENUM("Stereo1 DD R Source", rt5665_sto1_dd_r_enum);
+
+/* MONO ADC L2 Source */
+/* MX-27 [12] */
+static const char * const rt5665_mono_adc_l2_src[] = {
+       "DAC MIXL", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_adc_l2_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_ADC_L2_SRC_SFT, rt5665_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l2_mux =
+       SOC_DAPM_ENUM("Mono ADC L2 Source", rt5665_mono_adc_l2_enum);
+
+
+/* MONO ADC L1 Source */
+/* MX-27 [13] */
+static const char * const rt5665_mono_adc_l1_src[] = {
+       "DD Mux", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_adc_l1_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_ADC_L1_SRC_SFT, rt5665_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l1_mux =
+       SOC_DAPM_ENUM("Mono ADC L1 Source", rt5665_mono_adc_l1_enum);
+
+/* MX-27 [9][1]*/
+static const char * const rt5665_mono_dd_src[] = {
+       "STO2 DAC", "MONO DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_dd_l_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_DD_L_SRC_SFT, rt5665_mono_dd_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dd_l_mux =
+       SOC_DAPM_ENUM("Mono DD L Source", rt5665_mono_dd_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_dd_r_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_DD_R_SRC_SFT, rt5665_mono_dd_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dd_r_mux =
+       SOC_DAPM_ENUM("Mono DD R Source", rt5665_mono_dd_r_enum);
+
+/* MONO ADC L Source, MONO ADC R Source*/
+/* MX-27 [11:10], MX-27 [3:2] */
+static const char * const rt5665_mono_adc_src[] = {
+       "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_adc_l_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_ADC_L_SRC_SFT, rt5665_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_l_mux =
+       SOC_DAPM_ENUM("Mono ADC L Source", rt5665_mono_adc_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_adcr_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_ADC_R_SRC_SFT, rt5665_mono_adc_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r_mux =
+       SOC_DAPM_ENUM("Mono ADC R Source", rt5665_mono_adcr_enum);
+
+/* MONO DMIC L Source */
+/* MX-27 [8] */
+static const char * const rt5665_mono_dmic_l_src[] = {
+       "DMIC1 L", "DMIC2 L"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_dmic_l_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_DMIC_L_SRC_SFT, rt5665_mono_dmic_l_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dmic_l_mux =
+       SOC_DAPM_ENUM("Mono DMIC L Source", rt5665_mono_dmic_l_enum);
+
+/* MONO ADC R2 Source */
+/* MX-27 [4] */
+static const char * const rt5665_mono_adc_r2_src[] = {
+       "DAC MIXR", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_adc_r2_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_ADC_R2_SRC_SFT, rt5665_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r2_mux =
+       SOC_DAPM_ENUM("Mono ADC R2 Source", rt5665_mono_adc_r2_enum);
+
+/* MONO ADC R1 Source */
+/* MX-27 [5] */
+static const char * const rt5665_mono_adc_r1_src[] = {
+       "DD Mux", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_adc_r1_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_ADC_R1_SRC_SFT, rt5665_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5665_mono_adc_r1_mux =
+       SOC_DAPM_ENUM("Mono ADC R1 Source", rt5665_mono_adc_r1_enum);
+
+/* MONO DMIC R Source */
+/* MX-27 [0] */
+static const char * const rt5665_mono_dmic_r_src[] = {
+       "DMIC1 R", "DMIC2 R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_mono_dmic_r_enum, RT5665_MONO_ADC_MIXER,
+       RT5665_MONO_DMIC_R_SRC_SFT, rt5665_mono_dmic_r_src);
+
+static const struct snd_kcontrol_new rt5665_mono_dmic_r_mux =
+       SOC_DAPM_ENUM("Mono DMIC R Source", rt5665_mono_dmic_r_enum);
+
+
+/* STO2 ADC1 Source */
+/* MX-28 [13] [5] */
+static const char * const rt5665_sto2_adc1_src[] = {
+       "DD Mux", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_adc1l_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_ADC1L_SRC_SFT, rt5665_sto2_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc1l_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_adc1r_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_ADC1R_SRC_SFT, rt5665_sto2_adc1_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc1r_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1r_enum);
+
+/* STO2 ADC Source */
+/* MX-28 [11:10] [3:2] */
+static const char * const rt5665_sto2_adc_src[] = {
+       "ADC1 L", "ADC1 R", "ADC2 L"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_adcl_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_ADCL_SRC_SFT, rt5665_sto2_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adcl_mux =
+       SOC_DAPM_ENUM("Stereo2 ADCL Source", rt5665_sto2_adcl_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_adcr_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_ADCR_SRC_SFT, rt5665_sto2_adc_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adcr_mux =
+       SOC_DAPM_ENUM("Stereo2 ADCR Source", rt5665_sto2_adcr_enum);
+
+/* STO2 ADC2 Source */
+/* MX-28 [12] [4] */
+static const char * const rt5665_sto2_adc2_src[] = {
+       "DAC MIX", "DMIC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_adc2l_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_ADC2L_SRC_SFT, rt5665_sto2_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc2l_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC2L Source", rt5665_sto2_adc2l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_adc2r_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_ADC2R_SRC_SFT, rt5665_sto2_adc2_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_adc2r_mux =
+       SOC_DAPM_ENUM("Stereo2 ADC2R Source", rt5665_sto2_adc2r_enum);
+
+/* STO2 DMIC Source */
+/* MX-28 [8] */
+static const char * const rt5665_sto2_dmic_src[] = {
+       "DMIC1", "DMIC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_dmic_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_DMIC_SRC_SFT, rt5665_sto2_dmic_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_dmic_mux =
+       SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5665_sto2_dmic_enum);
+
+/* MX-28 [9] */
+static const char * const rt5665_sto2_dd_l_src[] = {
+       "STO2 DAC", "MONO DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_dd_l_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_DD_L_SRC_SFT, rt5665_sto2_dd_l_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_dd_l_mux =
+       SOC_DAPM_ENUM("Stereo2 DD L Source", rt5665_sto2_dd_l_enum);
+
+/* MX-28 [1] */
+static const char * const rt5665_sto2_dd_r_src[] = {
+       "STO2 DAC", "MONO DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_sto2_dd_r_enum, RT5665_STO2_ADC_MIXER,
+       RT5665_STO2_DD_R_SRC_SFT, rt5665_sto2_dd_r_src);
+
+static const struct snd_kcontrol_new rt5665_sto2_dd_r_mux =
+       SOC_DAPM_ENUM("Stereo2 DD R Source", rt5665_sto2_dd_r_enum);
+
+/* DAC R1 Source, DAC L1 Source*/
+/* MX-29 [11:10], MX-29 [9:8]*/
+static const char * const rt5665_dac1_src[] = {
+       "IF1 DAC1", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dac_r1_enum, RT5665_AD_DA_MIXER,
+       RT5665_DAC1_R_SEL_SFT, rt5665_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_dac_r1_mux =
+       SOC_DAPM_ENUM("DAC R1 Source", rt5665_dac_r1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dac_l1_enum, RT5665_AD_DA_MIXER,
+       RT5665_DAC1_L_SEL_SFT, rt5665_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_dac_l1_mux =
+       SOC_DAPM_ENUM("DAC L1 Source", rt5665_dac_l1_enum);
+
+/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/
+/* MX-2D [13:12], MX-2D [9:8]*/
+static const char * const rt5665_dig_dac_mix_src[] = {
+       "Stereo1 DAC Mixer", "Stereo2 DAC Mixer", "Mono DAC Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dig_dac_mixl_enum, RT5665_A_DAC1_MUX,
+       RT5665_DAC_MIX_L_SFT, rt5665_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5665_dig_dac_mixl_mux =
+       SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5665_dig_dac_mixl_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_dig_dac_mixr_enum, RT5665_A_DAC1_MUX,
+       RT5665_DAC_MIX_R_SFT, rt5665_dig_dac_mix_src);
+
+static const struct snd_kcontrol_new rt5665_dig_dac_mixr_mux =
+       SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5665_dig_dac_mixr_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2D [5:4], MX-2D [1:0]*/
+static const char * const rt5665_alg_dac1_src[] = {
+       "Stereo1 DAC Mixer", "DAC1", "DMIC1"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_alg_dac_l1_enum, RT5665_A_DAC1_MUX,
+       RT5665_A_DACL1_SFT, rt5665_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_l1_mux =
+       SOC_DAPM_ENUM("Analog DAC L1 Source", rt5665_alg_dac_l1_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_alg_dac_r1_enum, RT5665_A_DAC1_MUX,
+       RT5665_A_DACR1_SFT, rt5665_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_r1_mux =
+       SOC_DAPM_ENUM("Analog DAC R1 Source", rt5665_alg_dac_r1_enum);
+
+/* Analog DAC LR Source, Analog DAC R2 Source*/
+/* MX-2E [5:4], MX-2E [0]*/
+static const char * const rt5665_alg_dac2_src[] = {
+       "Mono DAC Mixer", "DAC2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_alg_dac_l2_enum, RT5665_A_DAC2_MUX,
+       RT5665_A_DACL2_SFT, rt5665_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_l2_mux =
+       SOC_DAPM_ENUM("Analog DAC L2 Source", rt5665_alg_dac_l2_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_alg_dac_r2_enum, RT5665_A_DAC2_MUX,
+       RT5665_A_DACR2_SFT, rt5665_alg_dac2_src);
+
+static const struct snd_kcontrol_new rt5665_alg_dac_r2_mux =
+       SOC_DAPM_ENUM("Analog DAC R2 Source", rt5665_alg_dac_r2_enum);
+
+/* Interface2 ADC Data Input*/
+/* MX-2F [14:12] */
+static const char * const rt5665_if2_1_adc_in_src[] = {
+       "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1",
+       "IF1 DAC2", "IF2_2 DAC", "IF3 DAC", "DAC1 MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if2_1_adc_in_enum, RT5665_DIG_INF2_DATA,
+       RT5665_IF3_ADC_IN_SFT, rt5665_if2_1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5665_if2_1_adc_in_mux =
+       SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_1_adc_in_enum);
+
+/* MX-2F [6:4] */
+static const char * const rt5665_if2_2_adc_in_src[] = {
+       "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1",
+       "IF1 DAC2", "IF2_1 DAC", "IF3 DAC", "DAC1 MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if2_2_adc_in_enum, RT5665_DIG_INF2_DATA,
+       RT5665_IF2_2_ADC_IN_SFT, rt5665_if2_2_adc_in_src);
+
+static const struct snd_kcontrol_new rt5665_if2_2_adc_in_mux =
+       SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_2_adc_in_enum);
+
+/* Interface3 ADC Data Input*/
+/* MX-30 [6:4] */
+static const char * const rt5665_if3_adc_in_src[] = {
+       "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1",
+       "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "DAC1 MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if3_adc_in_enum, RT5665_DIG_INF3_DATA,
+       RT5665_IF3_ADC_IN_SFT, rt5665_if3_adc_in_src);
+
+static const struct snd_kcontrol_new rt5665_if3_adc_in_mux =
+       SOC_DAPM_ENUM("IF3 ADC IN Source", rt5665_if3_adc_in_enum);
+
+/* PDM 1 L/R*/
+/* MX-31 [11:10] [9:8] */
+static const char * const rt5665_pdm_src[] = {
+       "Stereo1 DAC", "Stereo2 DAC", "Mono DAC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_pdm_l_enum, RT5665_PDM_OUT_CTRL,
+       RT5665_PDM1_L_SFT, rt5665_pdm_src);
+
+static const struct snd_kcontrol_new rt5665_pdm_l_mux =
+       SOC_DAPM_ENUM("PDM L Source", rt5665_pdm_l_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_pdm_r_enum, RT5665_PDM_OUT_CTRL,
+       RT5665_PDM1_R_SFT, rt5665_pdm_src);
+
+static const struct snd_kcontrol_new rt5665_pdm_r_mux =
+       SOC_DAPM_ENUM("PDM R Source", rt5665_pdm_r_enum);
+
+
+/* I2S1 TDM ADCDAT Source */
+/* MX-7a[10] */
+static const char * const rt5665_if1_1_adc1_data_src[] = {
+       "STO1 ADC", "IF2_1 DAC",
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if1_1_adc1_data_enum, RT5665_TDM_CTRL_3,
+       RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_1_adc1_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_1_adc1_mux =
+       SOC_DAPM_ENUM("IF1_1 ADC1 Source", rt5665_if1_1_adc1_data_enum);
+
+/* MX-7a[9] */
+static const char * const rt5665_if1_1_adc2_data_src[] = {
+       "STO2 ADC", "IF2_2 DAC",
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if1_1_adc2_data_enum, RT5665_TDM_CTRL_3,
+       RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_1_adc2_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_1_adc2_mux =
+       SOC_DAPM_ENUM("IF1_1 ADC2 Source", rt5665_if1_1_adc2_data_enum);
+
+/* MX-7a[8] */
+static const char * const rt5665_if1_1_adc3_data_src[] = {
+       "MONO ADC", "IF3 DAC",
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if1_1_adc3_data_enum, RT5665_TDM_CTRL_3,
+       RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_1_adc3_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_1_adc3_mux =
+       SOC_DAPM_ENUM("IF1_1 ADC3 Source", rt5665_if1_1_adc3_data_enum);
+
+/* MX-7b[10] */
+static const char * const rt5665_if1_2_adc1_data_src[] = {
+       "STO1 ADC", "IF1 DAC",
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if1_2_adc1_data_enum, RT5665_TDM_CTRL_4,
+       RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_2_adc1_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc1_mux =
+       SOC_DAPM_ENUM("IF1_2 ADC1 Source", rt5665_if1_2_adc1_data_enum);
+
+/* MX-7b[9] */
+static const char * const rt5665_if1_2_adc2_data_src[] = {
+       "STO2 ADC", "IF2_1 DAC",
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if1_2_adc2_data_enum, RT5665_TDM_CTRL_4,
+       RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_2_adc2_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc2_mux =
+       SOC_DAPM_ENUM("IF1_2 ADC2 Source", rt5665_if1_2_adc2_data_enum);
+
+/* MX-7b[8] */
+static const char * const rt5665_if1_2_adc3_data_src[] = {
+       "MONO ADC", "IF2_2 DAC",
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if1_2_adc3_data_enum, RT5665_TDM_CTRL_4,
+       RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_2_adc3_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc3_mux =
+       SOC_DAPM_ENUM("IF1_2 ADC3 Source", rt5665_if1_2_adc3_data_enum);
+
+/* MX-7b[7] */
+static const char * const rt5665_if1_2_adc4_data_src[] = {
+       "DAC1", "IF3 DAC",
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_if1_2_adc4_data_enum, RT5665_TDM_CTRL_4,
+       RT5665_IF1_ADC4_SEL_SFT, rt5665_if1_2_adc4_data_src);
+
+static const struct snd_kcontrol_new rt5665_if1_2_adc4_mux =
+       SOC_DAPM_ENUM("IF1_2 ADC4 Source", rt5665_if1_2_adc4_data_enum);
+
+/* MX-7a[4:0] MX-7b[4:0] */
+static const char * const rt5665_tdm_adc_data_src[] = {
+       "1234", "1243", "1324", "1342", "1432", "1423",
+       "2134", "2143", "2314", "2341", "2431", "2413",
+       "3124", "3142", "3214", "3241", "3412", "3421",
+       "4123", "4132", "4213", "4231", "4312", "4321"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_tdm1_adc_data_enum, RT5665_TDM_CTRL_3,
+       RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src);
+
+static const struct snd_kcontrol_new rt5665_tdm1_adc_mux =
+       SOC_DAPM_ENUM("TDM1 ADC Mux", rt5665_tdm1_adc_data_enum);
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5665_tdm2_adc_data_enum, RT5665_TDM_CTRL_4,
+       RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src);
+
+static const struct snd_kcontrol_new rt5665_tdm2_adc_mux =
+       SOC_DAPM_ENUM("TDM2 ADCDAT Source", rt5665_tdm2_adc_data_enum);
+
+/* Out Volume Switch */
+static const struct snd_kcontrol_new monovol_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new outvol_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_R_SFT, 1, 1);
+
+/* Out Switch */
+static const struct snd_kcontrol_new mono_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hpo_switch =
+       SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5665_HP_CTRL_2,
+                                       RT5665_VOL_L_SFT, 1, 0);
+
+static const struct snd_kcontrol_new lout_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new lout_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm_l_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL,
+                       RT5665_M_PDM1_L_SFT, 1, 1);
+
+static const struct snd_kcontrol_new pdm_r_switch =
+       SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL,
+                       RT5665_M_PDM1_R_SFT, 1, 1);
+
+static int rt5665_mono_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+               snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
+                       0x0);
+               snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0x10);
+               snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0x20);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0);
+               snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0);
+               snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40,
+                       0x40);
+               snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+}
+
+static int rt5665_hp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_EN);
+               snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0003);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0002);
+               snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1,
+                       RT5665_NG2_EN_MASK, RT5665_NG2_DIS);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+}
+
+static int rt5665_lout_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RT5665_DEPOP_1,
+                       RT5665_PUMP_EN, RT5665_PUMP_EN);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, RT5665_DEPOP_1,
+                       RT5665_PUMP_EN, 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /*Add delay to avoid pop noise*/
+               msleep(150);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               switch (w->shift) {
+               case RT5665_PWR_VREF1_BIT:
+                       snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+                               RT5665_PWR_FV1, 0);
+                       break;
+
+               case RT5665_PWR_VREF2_BIT:
+                       snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+                               RT5665_PWR_FV2, 0);
+                       break;
+
+               case RT5665_PWR_VREF3_BIT:
+                       snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+                               RT5665_PWR_FV3, 0);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
+               usleep_range(15000, 20000);
+               switch (w->shift) {
+               case RT5665_PWR_VREF1_BIT:
+                       snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+                               RT5665_PWR_FV1, RT5665_PWR_FV1);
+                       break;
+
+               case RT5665_PWR_VREF2_BIT:
+                       snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+                               RT5665_PWR_FV2, RT5665_PWR_FV2);
+                       break;
+
+               case RT5665_PWR_VREF3_BIT:
+                       snd_soc_update_bits(codec, RT5665_PWR_ANLG_1,
+                               RT5665_PWR_FV3, RT5665_PWR_FV3);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+
+static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("LDO2", RT5665_PWR_ANLG_3, RT5665_PWR_LDO2_BIT, 0,
+               NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLL", RT5665_PWR_ANLG_3, RT5665_PWR_PLL_BIT, 0,
+               NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL,
+               RT5665_PWR_MIC_DET_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0,
+               rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0,
+               rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0,
+               rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+       /* ASRC */
+       SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1,
+               RT5665_I2S1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5665_ASRC_1,
+               RT5665_I2S2_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5665_ASRC_1,
+               RT5665_I2S3_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5665_ASRC_1,
+               RT5665_DAC_STO1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC STO2 ASRC", 1, RT5665_ASRC_1,
+               RT5665_DAC_STO2_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5665_ASRC_1,
+               RT5665_DAC_MONO_L_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5665_ASRC_1,
+               RT5665_DAC_MONO_R_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5665_ASRC_1,
+               RT5665_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5665_ASRC_1,
+               RT5665_ADC_MONO_L_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5665_ASRC_1,
+               RT5665_ADC_MONO_R_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5665_ASRC_1,
+               RT5665_DMIC_STO1_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5665_ASRC_1,
+               RT5665_DMIC_STO2_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5665_ASRC_1,
+               RT5665_DMIC_MONO_L_ASRC_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5665_ASRC_1,
+               RT5665_DMIC_MONO_R_ASRC_SFT, 0, NULL, 0),
+
+       /* Input Side */
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5665_PWR_ANLG_2, RT5665_PWR_MB1_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5665_PWR_ANLG_2, RT5665_PWR_MB2_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5665_PWR_ANLG_2, RT5665_PWR_MB3_BIT,
+               0, NULL, 0),
+
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("DMIC L1"),
+       SND_SOC_DAPM_INPUT("DMIC R1"),
+       SND_SOC_DAPM_INPUT("DMIC L2"),
+       SND_SOC_DAPM_INPUT("DMIC R2"),
+
+       SND_SOC_DAPM_INPUT("IN1P"),
+       SND_SOC_DAPM_INPUT("IN1N"),
+       SND_SOC_DAPM_INPUT("IN2P"),
+       SND_SOC_DAPM_INPUT("IN2N"),
+       SND_SOC_DAPM_INPUT("IN3P"),
+       SND_SOC_DAPM_INPUT("IN3N"),
+       SND_SOC_DAPM_INPUT("IN4P"),
+       SND_SOC_DAPM_INPUT("IN4N"),
+
+       SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+               set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5665_DMIC_CTRL_1,
+               RT5665_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5665_DMIC_CTRL_1,
+               RT5665_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+       /* Boost */
+       SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST3", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST4", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM,
+               0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST1 Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST2 Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST3 Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST3_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST4 Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST4_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST1P Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST1_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST2P Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST2_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST3P Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST3_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("BST4P Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_BST4_P_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CBJ Power", RT5665_PWR_ANLG_3,
+               RT5665_PWR_CBJ_BIT, 0, NULL, 0),
+
+
+       /* Input Volume */
+       SND_SOC_DAPM_PGA("INL VOL", RT5665_PWR_VOL, RT5665_PWR_IN_L_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR VOL", RT5665_PWR_VOL, RT5665_PWR_IN_R_BIT,
+               0, NULL, 0),
+
+       /* REC Mixer */
+       SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5665_rec1_l_mix,
+               ARRAY_SIZE(rt5665_rec1_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5665_rec1_r_mix,
+               ARRAY_SIZE(rt5665_rec1_r_mix)),
+       SND_SOC_DAPM_MIXER("RECMIX2L", SND_SOC_NOPM, 0, 0, rt5665_rec2_l_mix,
+               ARRAY_SIZE(rt5665_rec2_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIX2R", SND_SOC_NOPM, 0, 0, rt5665_rec2_r_mix,
+               ARRAY_SIZE(rt5665_rec2_r_mix)),
+       SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_RM1_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5665_PWR_ANLG_2,
+               RT5665_PWR_RM1_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RECMIX2L Power", RT5665_PWR_MIXER,
+               RT5665_PWR_RM2_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RECMIX2R Power", RT5665_PWR_MIXER,
+               RT5665_PWR_RM2_R_BIT, 0, NULL, 0),
+
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5665_PWR_DIG_1,
+               RT5665_PWR_ADC_L1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5665_PWR_DIG_1,
+               RT5665_PWR_ADC_R1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5665_PWR_DIG_1,
+               RT5665_PWR_ADC_L2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5665_PWR_DIG_1,
+               RT5665_PWR_ADC_R2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5665_CHOP_ADC,
+               RT5665_CKGEN_ADC1_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC2 clock", RT5665_CHOP_ADC,
+               RT5665_CKGEN_ADC2_SFT, 0, NULL, 0),
+
+       /* ADC Mux */
+       SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_dmic_mux),
+       SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_dmic_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_adc1l_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_adc1r_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_adc2l_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_adc2r_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_adcl_mux),
+       SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_adcr_mux),
+       SND_SOC_DAPM_MUX("Stereo1 DD L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_dd_l_mux),
+       SND_SOC_DAPM_MUX("Stereo1 DD R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto1_dd_r_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_adc_l2_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_adc_r2_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_adc_l1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_adc_r1_mux),
+       SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_dmic_l_mux),
+       SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_dmic_r_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_adc_l_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_adc_r_mux),
+       SND_SOC_DAPM_MUX("Mono DD L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_dd_l_mux),
+       SND_SOC_DAPM_MUX("Mono DD R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_mono_dd_r_mux),
+       SND_SOC_DAPM_MUX("Stereo2 DMIC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_dmic_mux),
+       SND_SOC_DAPM_MUX("Stereo2 DMIC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_dmic_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_adc1l_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_adc1r_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_adc2l_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_adc2r_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_adcl_mux),
+       SND_SOC_DAPM_MUX("Stereo2 ADC R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_adcr_mux),
+       SND_SOC_DAPM_MUX("Stereo2 DD L Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_dd_l_mux),
+       SND_SOC_DAPM_MUX("Stereo2 DD R Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_sto2_dd_r_mux),
+       /* ADC Mixer */
+       SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_ADC_S1F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_ADC_S2F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5665_STO1_ADC_DIG_VOL,
+               RT5665_L_MUTE_SFT, 1, rt5665_sto1_adc_l_mix,
+               ARRAY_SIZE(rt5665_sto1_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5665_STO1_ADC_DIG_VOL,
+               RT5665_R_MUTE_SFT, 1, rt5665_sto1_adc_r_mix,
+               ARRAY_SIZE(rt5665_sto1_adc_r_mix)),
+       SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", RT5665_STO2_ADC_DIG_VOL,
+               RT5665_L_MUTE_SFT, 1, rt5665_sto2_adc_l_mix,
+               ARRAY_SIZE(rt5665_sto2_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", RT5665_STO2_ADC_DIG_VOL,
+               RT5665_R_MUTE_SFT, 1, rt5665_sto2_adc_r_mix,
+               ARRAY_SIZE(rt5665_sto2_adc_r_mix)),
+       SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5665_MONO_ADC_DIG_VOL,
+               RT5665_L_MUTE_SFT, 1, rt5665_mono_adc_l_mix,
+               ARRAY_SIZE(rt5665_mono_adc_l_mix)),
+       SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5665_MONO_ADC_DIG_VOL,
+               RT5665_R_MUTE_SFT, 1, rt5665_mono_adc_r_mix,
+               ARRAY_SIZE(rt5665_mono_adc_r_mix)),
+
+       /* ADC PGA */
+       SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SUPPLY("I2S1_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_1_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S1_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_2_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S2_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_1_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S2_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_2_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S3", RT5665_PWR_DIG_1, RT5665_PWR_I2S3_BIT,
+               0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC3", 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 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC3 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("IF2_1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2_2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2_1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2_1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2_2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2_2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2_1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2_2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* Digital Interface Select */
+       SND_SOC_DAPM_MUX("IF1_1_ADC1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if1_1_adc1_mux),
+       SND_SOC_DAPM_MUX("IF1_1_ADC2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if1_1_adc2_mux),
+       SND_SOC_DAPM_MUX("IF1_1_ADC3 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if1_1_adc3_mux),
+       SND_SOC_DAPM_PGA("IF1_1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("IF1_2_ADC1 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if1_2_adc1_mux),
+       SND_SOC_DAPM_MUX("IF1_2_ADC2 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if1_2_adc2_mux),
+       SND_SOC_DAPM_MUX("IF1_2_ADC3 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if1_2_adc3_mux),
+       SND_SOC_DAPM_MUX("IF1_2_ADC4 Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if1_2_adc4_mux),
+       SND_SOC_DAPM_MUX("TDM1 slot 01 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm1_adc_mux),
+       SND_SOC_DAPM_MUX("TDM1 slot 23 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm1_adc_mux),
+       SND_SOC_DAPM_MUX("TDM1 slot 45 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm1_adc_mux),
+       SND_SOC_DAPM_MUX("TDM1 slot 67 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm1_adc_mux),
+       SND_SOC_DAPM_MUX("TDM2 slot 01 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm2_adc_mux),
+       SND_SOC_DAPM_MUX("TDM2 slot 23 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm2_adc_mux),
+       SND_SOC_DAPM_MUX("TDM2 slot 45 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm2_adc_mux),
+       SND_SOC_DAPM_MUX("TDM2 slot 67 Data Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_tdm2_adc_mux),
+       SND_SOC_DAPM_MUX("IF2_1 ADC Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if2_1_adc_in_mux),
+       SND_SOC_DAPM_MUX("IF2_2 ADC Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if2_2_adc_in_mux),
+       SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
+               &rt5665_if3_adc_in_mux),
+       SND_SOC_DAPM_MUX("IF1_1 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_01_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_1 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_01_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_1 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_23_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_1 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_23_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_1 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_45_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_1 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_45_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_1 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_67_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_1 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_1_67_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_01_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_01_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_23_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_23_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_45_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_45_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_67_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF1_2 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if1_2_67_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF2_1 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if2_1_dac_swap_mux),
+       SND_SOC_DAPM_MUX("IF2_1 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if2_1_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF2_2 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if2_2_dac_swap_mux),
+       SND_SOC_DAPM_MUX("IF2_2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if2_2_adc_swap_mux),
+       SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if3_dac_swap_mux),
+       SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+                       &rt5665_if3_adc_swap_mux),
+
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 0", "AIF1_1 Capture",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 1", "AIF1_1 Capture",
+                               1, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 2", "AIF1_1 Capture",
+                               2, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 3", "AIF1_1 Capture",
+                               3, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 4", "AIF1_1 Capture",
+                               4, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 5", "AIF1_1 Capture",
+                               5, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 6", "AIF1_1 Capture",
+                               6, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 7", "AIF1_1 Capture",
+                               7, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 0", "AIF1_2 Capture",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 1", "AIF1_2 Capture",
+                               1, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 2", "AIF1_2 Capture",
+                               2, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 3", "AIF1_2 Capture",
+                               3, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 4", "AIF1_2 Capture",
+                               4, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 5", "AIF1_2 Capture",
+                               5, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 6", "AIF1_2 Capture",
+                               6, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 7", "AIF1_2 Capture",
+                               7, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF2_1TX", "AIF2_1 Capture",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF2_2TX", "AIF2_2 Capture",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF2_1RX", "AIF2_1 Playback",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF2_2RX", "AIF2_2 Playback",
+                               0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback",
+                               0, SND_SOC_NOPM, 0, 0),
+
+       /* Output Side */
+       /* DAC mixer before sound effect  */
+       SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+               rt5665_dac_l_mix, ARRAY_SIZE(rt5665_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+               rt5665_dac_r_mix, ARRAY_SIZE(rt5665_dac_r_mix)),
+
+       /* DAC channel Mux */
+       SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l1_mux),
+       SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r1_mux),
+       SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r2_mux),
+       SND_SOC_DAPM_MUX("DAC L3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l3_mux),
+       SND_SOC_DAPM_MUX("DAC R3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r3_mux),
+
+       SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+               &rt5665_alg_dac_l1_mux),
+       SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+               &rt5665_alg_dac_r1_mux),
+       SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0,
+               &rt5665_alg_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0,
+               &rt5665_alg_dac_r2_mux),
+
+       /* DAC Mixer */
+       SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_DAC_S1F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC Stereo2 Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_DAC_S2F_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_DAC_MF_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5665_PWR_DIG_2,
+               RT5665_PWR_DAC_MF_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5665_sto1_dac_l_mix, ARRAY_SIZE(rt5665_sto1_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5665_sto1_dac_r_mix, ARRAY_SIZE(rt5665_sto1_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("Stereo2 DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5665_sto2_dac_l_mix, ARRAY_SIZE(rt5665_sto2_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo2 DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5665_sto2_dac_r_mix, ARRAY_SIZE(rt5665_sto2_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5665_mono_dac_l_mix, ARRAY_SIZE(rt5665_mono_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5665_mono_dac_r_mix, ARRAY_SIZE(rt5665_mono_dac_r_mix)),
+       SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0,
+               &rt5665_dig_dac_mixl_mux),
+       SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0,
+               &rt5665_dig_dac_mixr_mux),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5665_PWR_DIG_1,
+               RT5665_PWR_DAC_L2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5665_PWR_DIG_1,
+               RT5665_PWR_DAC_R2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_PGA("DAC1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 1, RT5665_CHOP_DAC,
+               RT5665_CKGEN_DAC1_SFT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC 2 Clock", 1, RT5665_CHOP_DAC,
+               RT5665_CKGEN_DAC2_SFT, 0, NULL, 0),
+
+       /* OUT Mixer */
+       SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5665_PWR_MIXER, RT5665_PWR_MM_BIT,
+               0, rt5665_monovol_mix, ARRAY_SIZE(rt5665_monovol_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5665_PWR_MIXER, RT5665_PWR_OM_L_BIT,
+               0, rt5665_out_l_mix, ARRAY_SIZE(rt5665_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5665_PWR_MIXER, RT5665_PWR_OM_R_BIT,
+               0, rt5665_out_r_mix, ARRAY_SIZE(rt5665_out_r_mix)),
+
+       /* Output Volume */
+       SND_SOC_DAPM_SWITCH("MONOVOL", RT5665_PWR_VOL, RT5665_PWR_MV_BIT, 0,
+               &monovol_switch),
+       SND_SOC_DAPM_SWITCH("OUTVOL L", RT5665_PWR_VOL, RT5665_PWR_OV_L_BIT, 0,
+               &outvol_l_switch),
+       SND_SOC_DAPM_SWITCH("OUTVOL R", RT5665_PWR_VOL, RT5665_PWR_OV_R_BIT, 0,
+               &outvol_r_switch),
+
+       /* MONO/HPO/LOUT */
+       SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0, 0, rt5665_mono_mix,
+               ARRAY_SIZE(rt5665_mono_mix)),
+       SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_l_mix,
+               ARRAY_SIZE(rt5665_lout_l_mix)),
+       SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_r_mix,
+               ARRAY_SIZE(rt5665_lout_r_mix)),
+       SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5665_PWR_ANLG_1, RT5665_PWR_MA_BIT,
+               0, rt5665_mono_event, SND_SOC_DAPM_POST_PMD |
+               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5665_hp_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_PGA_S("LOUT Amp", 1, RT5665_PWR_ANLG_1,
+               RT5665_PWR_LM_BIT, 0, rt5665_lout_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+
+       SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0,
+               rt5665_charge_pump_event, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0,
+               &mono_switch),
+       SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0,
+               &hpo_switch),
+       SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0,
+               &lout_l_switch),
+       SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0,
+               &lout_r_switch),
+       SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0,
+               &pdm_l_switch),
+       SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0,
+               &pdm_r_switch),
+
+       /* PDM */
+       SND_SOC_DAPM_SUPPLY("PDM Power", RT5665_PWR_DIG_2,
+               RT5665_PWR_PDM1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("PDM L Mux", SND_SOC_NOPM,
+               0, 1, &rt5665_pdm_l_mux),
+       SND_SOC_DAPM_MUX("PDM R Mux", SND_SOC_NOPM,
+               0, 1, &rt5665_pdm_r_mux),
+
+       /* CLK DET */
+       SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5665_CLK_DET, RT5665_SYS_CLK_DET,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET HP", RT5665_CLK_DET, RT5665_HP_CLK_DET,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET MONO", RT5665_CLK_DET, RT5665_MONO_CLK_DET,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET LOUT", RT5665_CLK_DET, RT5665_LOUT_CLK_DET,
+               0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLKDET", RT5665_CLK_DET, RT5665_POW_CLK_DET,
+               0, NULL, 0),
+
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+       SND_SOC_DAPM_OUTPUT("LOUTL"),
+       SND_SOC_DAPM_OUTPUT("LOUTR"),
+       SND_SOC_DAPM_OUTPUT("MONOOUT"),
+       SND_SOC_DAPM_OUTPUT("PDML"),
+       SND_SOC_DAPM_OUTPUT("PDMR"),
+};
+
+static const struct snd_soc_dapm_route rt5665_dapm_routes[] = {
+       /*PLL*/
+       {"ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll},
+       {"ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll},
+       {"ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll},
+       {"ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll},
+       {"DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll},
+       {"DAC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll},
+       {"DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll},
+       {"DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll},
+
+       /*ASRC*/
+       {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
+       {"ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc},
+       {"ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc},
+       {"DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc},
+       {"DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc},
+       {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc},
+       {"DAC Stereo2 Filter", NULL, "DAC STO2 ASRC", is_using_asrc},
+
+       /*Vref*/
+       {"Mic Det Power", NULL, "Vref2"},
+       {"MICBIAS1", NULL, "Vref1"},
+       {"MICBIAS1", NULL, "Vref2"},
+       {"MICBIAS2", NULL, "Vref1"},
+       {"MICBIAS2", NULL, "Vref2"},
+       {"MICBIAS3", NULL, "Vref1"},
+       {"MICBIAS3", NULL, "Vref2"},
+
+       {"Stereo1 DMIC L Mux", NULL, "DMIC STO1 ASRC"},
+       {"Stereo1 DMIC R Mux", NULL, "DMIC STO1 ASRC"},
+       {"Stereo2 DMIC L Mux", NULL, "DMIC STO2 ASRC"},
+       {"Stereo2 DMIC R Mux", NULL, "DMIC STO2 ASRC"},
+       {"Mono DMIC L Mux", NULL, "DMIC MONO L ASRC"},
+       {"Mono DMIC R Mux", NULL, "DMIC MONO R ASRC"},
+
+       {"I2S1_1", NULL, "I2S1 ASRC"},
+       {"I2S1_2", NULL, "I2S1 ASRC"},
+       {"I2S2_1", NULL, "I2S2 ASRC"},
+       {"I2S2_2", NULL, "I2S2 ASRC"},
+       {"I2S3", NULL, "I2S3 ASRC"},
+
+       {"CLKDET SYS", NULL, "CLKDET"},
+       {"CLKDET HP", NULL, "CLKDET"},
+       {"CLKDET MONO", NULL, "CLKDET"},
+       {"CLKDET LOUT", NULL, "CLKDET"},
+
+       {"IN1P", NULL, "LDO2"},
+       {"IN2P", NULL, "LDO2"},
+       {"IN3P", NULL, "LDO2"},
+       {"IN4P", NULL, "LDO2"},
+
+       {"DMIC1", NULL, "DMIC L1"},
+       {"DMIC1", NULL, "DMIC R1"},
+       {"DMIC2", NULL, "DMIC L2"},
+       {"DMIC2", NULL, "DMIC R2"},
+
+       {"BST1", NULL, "IN1P"},
+       {"BST1", NULL, "IN1N"},
+       {"BST1", NULL, "BST1 Power"},
+       {"BST1", NULL, "BST1P Power"},
+       {"BST2", NULL, "IN2P"},
+       {"BST2", NULL, "IN2N"},
+       {"BST2", NULL, "BST2 Power"},
+       {"BST2", NULL, "BST2P Power"},
+       {"BST3", NULL, "IN3P"},
+       {"BST3", NULL, "IN3N"},
+       {"BST3", NULL, "BST3 Power"},
+       {"BST3", NULL, "BST3P Power"},
+       {"BST4", NULL, "IN4P"},
+       {"BST4", NULL, "IN4N"},
+       {"BST4", NULL, "BST4 Power"},
+       {"BST4", NULL, "BST4P Power"},
+       {"BST1 CBJ", NULL, "IN1P"},
+       {"BST1 CBJ", NULL, "IN1N"},
+       {"BST1 CBJ", NULL, "CBJ Power"},
+       {"CBJ Power", NULL, "Vref2"},
+
+       {"INL VOL", NULL, "IN3P"},
+       {"INR VOL", NULL, "IN3N"},
+
+       {"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
+       {"RECMIX1L", "INL Switch", "INL VOL"},
+       {"RECMIX1L", "INR Switch", "INR VOL"},
+       {"RECMIX1L", "BST4 Switch", "BST4"},
+       {"RECMIX1L", "BST3 Switch", "BST3"},
+       {"RECMIX1L", "BST2 Switch", "BST2"},
+       {"RECMIX1L", "BST1 Switch", "BST1"},
+       {"RECMIX1L", NULL, "RECMIX1L Power"},
+
+       {"RECMIX1R", "MONOVOL Switch", "MONOVOL"},
+       {"RECMIX1R", "INR Switch", "INR VOL"},
+       {"RECMIX1R", "BST4 Switch", "BST4"},
+       {"RECMIX1R", "BST3 Switch", "BST3"},
+       {"RECMIX1R", "BST2 Switch", "BST2"},
+       {"RECMIX1R", "BST1 Switch", "BST1"},
+       {"RECMIX1R", NULL, "RECMIX1R Power"},
+
+       {"RECMIX2L", "CBJ Switch", "BST1 CBJ"},
+       {"RECMIX2L", "INL Switch", "INL VOL"},
+       {"RECMIX2L", "INR Switch", "INR VOL"},
+       {"RECMIX2L", "BST4 Switch", "BST4"},
+       {"RECMIX2L", "BST3 Switch", "BST3"},
+       {"RECMIX2L", "BST2 Switch", "BST2"},
+       {"RECMIX2L", "BST1 Switch", "BST1"},
+       {"RECMIX2L", NULL, "RECMIX2L Power"},
+
+       {"RECMIX2R", "MONOVOL Switch", "MONOVOL"},
+       {"RECMIX2R", "INL Switch", "INL VOL"},
+       {"RECMIX2R", "INR Switch", "INR VOL"},
+       {"RECMIX2R", "BST4 Switch", "BST4"},
+       {"RECMIX2R", "BST3 Switch", "BST3"},
+       {"RECMIX2R", "BST2 Switch", "BST2"},
+       {"RECMIX2R", "BST1 Switch", "BST1"},
+       {"RECMIX2R", NULL, "RECMIX2R Power"},
+
+       {"ADC1 L", NULL, "RECMIX1L"},
+       {"ADC1 L", NULL, "ADC1 L Power"},
+       {"ADC1 L", NULL, "ADC1 clock"},
+       {"ADC1 R", NULL, "RECMIX1R"},
+       {"ADC1 R", NULL, "ADC1 R Power"},
+       {"ADC1 R", NULL, "ADC1 clock"},
+
+       {"ADC2 L", NULL, "RECMIX2L"},
+       {"ADC2 L", NULL, "ADC2 L Power"},
+       {"ADC2 L", NULL, "ADC2 clock"},
+       {"ADC2 R", NULL, "RECMIX2R"},
+       {"ADC2 R", NULL, "ADC2 R Power"},
+       {"ADC2 R", NULL, "ADC2 clock"},
+
+       {"DMIC L1", NULL, "DMIC CLK"},
+       {"DMIC L1", NULL, "DMIC1 Power"},
+       {"DMIC R1", NULL, "DMIC CLK"},
+       {"DMIC R1", NULL, "DMIC1 Power"},
+       {"DMIC L2", NULL, "DMIC CLK"},
+       {"DMIC L2", NULL, "DMIC2 Power"},
+       {"DMIC R2", NULL, "DMIC CLK"},
+       {"DMIC R2", NULL, "DMIC2 Power"},
+
+       {"Stereo1 DMIC L Mux", "DMIC1", "DMIC L1"},
+       {"Stereo1 DMIC L Mux", "DMIC2", "DMIC L2"},
+
+       {"Stereo1 DMIC R Mux", "DMIC1", "DMIC R1"},
+       {"Stereo1 DMIC R Mux", "DMIC2", "DMIC R2"},
+
+       {"Mono DMIC L Mux", "DMIC1 L", "DMIC L1"},
+       {"Mono DMIC L Mux", "DMIC2 L", "DMIC L2"},
+
+       {"Mono DMIC R Mux", "DMIC1 R", "DMIC R1"},
+       {"Mono DMIC R Mux", "DMIC2 R", "DMIC R2"},
+
+       {"Stereo2 DMIC L Mux", "DMIC1", "DMIC L1"},
+       {"Stereo2 DMIC L Mux", "DMIC2", "DMIC L2"},
+
+       {"Stereo2 DMIC R Mux", "DMIC1", "DMIC R1"},
+       {"Stereo2 DMIC R Mux", "DMIC2", "DMIC R2"},
+
+       {"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"},
+       {"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"},
+       {"Stereo1 ADC L Mux", "ADC2 L", "ADC2 L"},
+       {"Stereo1 ADC L Mux", "ADC2 R", "ADC2 R"},
+       {"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"},
+       {"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"},
+       {"Stereo1 ADC R Mux", "ADC2 L", "ADC2 L"},
+       {"Stereo1 ADC R Mux", "ADC2 R", "ADC2 R"},
+
+       {"Stereo1 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"},
+       {"Stereo1 DD L Mux", "MONO DAC", "Mono DAC MIXL"},
+
+       {"Stereo1 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"},
+       {"Stereo1 DD R Mux", "MONO DAC", "Mono DAC MIXR"},
+
+       {"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"},
+       {"Stereo1 ADC L1 Mux", "DD Mux", "Stereo1 DD L Mux"},
+       {"Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux"},
+       {"Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL"},
+
+       {"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"},
+       {"Stereo1 ADC R1 Mux", "DD Mux", "Stereo1 DD R Mux"},
+       {"Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux"},
+       {"Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR"},
+
+       {"Mono ADC L Mux", "ADC1 L", "ADC1 L"},
+       {"Mono ADC L Mux", "ADC1 R", "ADC1 R"},
+       {"Mono ADC L Mux", "ADC2 L", "ADC2 L"},
+       {"Mono ADC L Mux", "ADC2 R", "ADC2 R"},
+
+       {"Mono ADC R Mux", "ADC1 L", "ADC1 L"},
+       {"Mono ADC R Mux", "ADC1 R", "ADC1 R"},
+       {"Mono ADC R Mux", "ADC2 L", "ADC2 L"},
+       {"Mono ADC R Mux", "ADC2 R", "ADC2 R"},
+
+       {"Mono DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"},
+       {"Mono DD L Mux", "MONO DAC", "Mono DAC MIXL"},
+
+       {"Mono DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"},
+       {"Mono DD R Mux", "MONO DAC", "Mono DAC MIXR"},
+
+       {"Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux"},
+       {"Mono ADC L2 Mux", "DAC MIXL", "DAC MIXL"},
+       {"Mono ADC L1 Mux", "DD Mux", "Mono DD L Mux"},
+       {"Mono ADC L1 Mux", "ADC",  "Mono ADC L Mux"},
+
+       {"Mono ADC R1 Mux", "DD Mux", "Mono DD R Mux"},
+       {"Mono ADC R1 Mux", "ADC", "Mono ADC R Mux"},
+       {"Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux"},
+       {"Mono ADC R2 Mux", "DAC MIXR", "DAC MIXR"},
+
+       {"Stereo2 ADC L Mux", "ADC1 L", "ADC1 L"},
+       {"Stereo2 ADC L Mux", "ADC2 L", "ADC2 L"},
+       {"Stereo2 ADC L Mux", "ADC1 R", "ADC1 R"},
+       {"Stereo2 ADC R Mux", "ADC1 L", "ADC1 L"},
+       {"Stereo2 ADC R Mux", "ADC2 L", "ADC2 L"},
+       {"Stereo2 ADC R Mux", "ADC1 R", "ADC1 R"},
+
+       {"Stereo2 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"},
+       {"Stereo2 DD L Mux", "MONO DAC", "Mono DAC MIXL"},
+
+       {"Stereo2 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"},
+       {"Stereo2 DD R Mux", "MONO DAC", "Mono DAC MIXR"},
+
+       {"Stereo2 ADC L1 Mux", "ADC", "Stereo2 ADC L Mux"},
+       {"Stereo2 ADC L1 Mux", "DD Mux", "Stereo2 DD L Mux"},
+       {"Stereo2 ADC L2 Mux", "DMIC", "Stereo2 DMIC L Mux"},
+       {"Stereo2 ADC L2 Mux", "DAC MIX", "DAC MIXL"},
+
+       {"Stereo2 ADC R1 Mux", "ADC", "Stereo2 ADC R Mux"},
+       {"Stereo2 ADC R1 Mux", "DD Mux", "Stereo2 DD R Mux"},
+       {"Stereo2 ADC R2 Mux", "DMIC", "Stereo2 DMIC R Mux"},
+       {"Stereo2 ADC R2 Mux", "DAC MIX", "DAC MIXR"},
+
+       {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+       {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+       {"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"},
+
+       {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+       {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+       {"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
+
+       {"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
+       {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
+       {"Mono ADC MIXL", NULL, "ADC Mono Left Filter"},
+
+       {"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
+       {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
+       {"Mono ADC MIXR", NULL, "ADC Mono Right Filter"},
+
+       {"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"},
+       {"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"},
+       {"Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter"},
+
+       {"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"},
+       {"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"},
+       {"Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter"},
+
+       {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
+       {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
+       {"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL"},
+       {"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR"},
+       {"Mono ADC MIX", NULL, "Mono ADC MIXL"},
+       {"Mono ADC MIX", NULL, "Mono ADC MIXR"},
+
+       {"IF1_1_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+       {"IF1_1_ADC1 Mux", "IF2_1 DAC", "IF2_1 DAC"},
+       {"IF1_1_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+       {"IF1_1_ADC2 Mux", "IF2_2 DAC", "IF2_2 DAC"},
+       {"IF1_1_ADC3 Mux", "MONO ADC", "Mono ADC MIX"},
+       {"IF1_1_ADC3 Mux", "IF3 DAC", "IF3 DAC"},
+       {"IF1_1_ADC4", NULL, "DAC1 MIX"},
+
+       {"IF1_2_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+       {"IF1_2_ADC1 Mux", "IF1 DAC", "IF1 DAC1"},
+       {"IF1_2_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+       {"IF1_2_ADC2 Mux", "IF2_1 DAC", "IF2_1 DAC"},
+       {"IF1_2_ADC3 Mux", "MONO ADC", "Mono ADC MIX"},
+       {"IF1_2_ADC3 Mux", "IF2_2 DAC", "IF2_2 DAC"},
+       {"IF1_2_ADC4 Mux", "DAC1", "DAC1 MIX"},
+       {"IF1_2_ADC4 Mux", "IF3 DAC", "IF3 DAC"},
+
+       {"TDM1 slot 01 Data Mux", "1234", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 01 Data Mux", "1243", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 01 Data Mux", "1324", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 01 Data Mux", "1342", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 01 Data Mux", "1432", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 01 Data Mux", "1423", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 01 Data Mux", "2134", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 01 Data Mux", "2143", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 01 Data Mux", "2314", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 01 Data Mux", "2341", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 01 Data Mux", "2431", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 01 Data Mux", "2413", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 01 Data Mux", "3124", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 01 Data Mux", "3142", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 01 Data Mux", "3214", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 01 Data Mux", "3241", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 01 Data Mux", "3412", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 01 Data Mux", "3421", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 01 Data Mux", "4123", "IF1_1_ADC4"},
+       {"TDM1 slot 01 Data Mux", "4132", "IF1_1_ADC4"},
+       {"TDM1 slot 01 Data Mux", "4213", "IF1_1_ADC4"},
+       {"TDM1 slot 01 Data Mux", "4231", "IF1_1_ADC4"},
+       {"TDM1 slot 01 Data Mux", "4312", "IF1_1_ADC4"},
+       {"TDM1 slot 01 Data Mux", "4321", "IF1_1_ADC4"},
+       {"TDM1 slot 01 Data Mux", NULL, "I2S1_1"},
+
+       {"TDM1 slot 23 Data Mux", "1234", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 23 Data Mux", "1243", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 23 Data Mux", "1324", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 23 Data Mux", "1342", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 23 Data Mux", "1432", "IF1_1_ADC4"},
+       {"TDM1 slot 23 Data Mux", "1423", "IF1_1_ADC4"},
+       {"TDM1 slot 23 Data Mux", "2134", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 23 Data Mux", "2143", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 23 Data Mux", "2314", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 23 Data Mux", "2341", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 23 Data Mux", "2431", "IF1_1_ADC4"},
+       {"TDM1 slot 23 Data Mux", "2413", "IF1_1_ADC4"},
+       {"TDM1 slot 23 Data Mux", "3124", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 23 Data Mux", "3142", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 23 Data Mux", "3214", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 23 Data Mux", "3241", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 23 Data Mux", "3412", "IF1_1_ADC4"},
+       {"TDM1 slot 23 Data Mux", "3421", "IF1_1_ADC4"},
+       {"TDM1 slot 23 Data Mux", "4123", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 23 Data Mux", "4132", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 23 Data Mux", "4213", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 23 Data Mux", "4231", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 23 Data Mux", "4312", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 23 Data Mux", "4321", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 23 Data Mux", NULL, "I2S1_1"},
+
+       {"TDM1 slot 45 Data Mux", "1234", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 45 Data Mux", "1243", "IF1_1_ADC4"},
+       {"TDM1 slot 45 Data Mux", "1324", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 45 Data Mux", "1342", "IF1_1_ADC4"},
+       {"TDM1 slot 45 Data Mux", "1432", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 45 Data Mux", "1423", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 45 Data Mux", "2134", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 45 Data Mux", "2143", "IF1_1_ADC4"},
+       {"TDM1 slot 45 Data Mux", "2314", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 45 Data Mux", "2341", "IF1_1_ADC4"},
+       {"TDM1 slot 45 Data Mux", "2431", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 45 Data Mux", "2413", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 45 Data Mux", "3124", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 45 Data Mux", "3142", "IF1_1_ADC4"},
+       {"TDM1 slot 45 Data Mux", "3214", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 45 Data Mux", "3241", "IF1_1_ADC4"},
+       {"TDM1 slot 45 Data Mux", "3412", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 45 Data Mux", "3421", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 45 Data Mux", "4123", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 45 Data Mux", "4132", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 45 Data Mux", "4213", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 45 Data Mux", "4231", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 45 Data Mux", "4312", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 45 Data Mux", "4321", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 45 Data Mux", NULL, "I2S1_1"},
+
+       {"TDM1 slot 67 Data Mux", "1234", "IF1_1_ADC4"},
+       {"TDM1 slot 67 Data Mux", "1243", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 67 Data Mux", "1324", "IF1_1_ADC4"},
+       {"TDM1 slot 67 Data Mux", "1342", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 67 Data Mux", "1432", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 67 Data Mux", "1423", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 67 Data Mux", "2134", "IF1_1_ADC4"},
+       {"TDM1 slot 67 Data Mux", "2143", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 67 Data Mux", "2314", "IF1_1_ADC4"},
+       {"TDM1 slot 67 Data Mux", "2341", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 67 Data Mux", "2431", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 67 Data Mux", "2413", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 67 Data Mux", "3124", "IF1_1_ADC4"},
+       {"TDM1 slot 67 Data Mux", "3142", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 67 Data Mux", "3214", "IF1_1_ADC4"},
+       {"TDM1 slot 67 Data Mux", "3241", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 67 Data Mux", "3412", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 67 Data Mux", "3421", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 67 Data Mux", "4123", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 67 Data Mux", "4132", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 67 Data Mux", "4213", "IF1_1_ADC3 Mux"},
+       {"TDM1 slot 67 Data Mux", "4231", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 67 Data Mux", "4312", "IF1_1_ADC2 Mux"},
+       {"TDM1 slot 67 Data Mux", "4321", "IF1_1_ADC1 Mux"},
+       {"TDM1 slot 67 Data Mux", NULL, "I2S1_1"},
+
+
+       {"TDM2 slot 01 Data Mux", "1234", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 01 Data Mux", "1243", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 01 Data Mux", "1324", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 01 Data Mux", "1342", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 01 Data Mux", "1432", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 01 Data Mux", "1423", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 01 Data Mux", "2134", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 01 Data Mux", "2143", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 01 Data Mux", "2314", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 01 Data Mux", "2341", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 01 Data Mux", "2431", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 01 Data Mux", "2413", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 01 Data Mux", "3124", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 01 Data Mux", "3142", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 01 Data Mux", "3214", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 01 Data Mux", "3241", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 01 Data Mux", "3412", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 01 Data Mux", "3421", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 01 Data Mux", "4123", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 01 Data Mux", "4132", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 01 Data Mux", "4213", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 01 Data Mux", "4231", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 01 Data Mux", "4312", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 01 Data Mux", "4321", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 01 Data Mux", NULL, "I2S1_2"},
+
+       {"TDM2 slot 23 Data Mux", "1234", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 23 Data Mux", "1243", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 23 Data Mux", "1324", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 23 Data Mux", "1342", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 23 Data Mux", "1432", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 23 Data Mux", "1423", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 23 Data Mux", "2134", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 23 Data Mux", "2143", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 23 Data Mux", "2314", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 23 Data Mux", "2341", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 23 Data Mux", "2431", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 23 Data Mux", "2413", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 23 Data Mux", "3124", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 23 Data Mux", "3142", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 23 Data Mux", "3214", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 23 Data Mux", "3241", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 23 Data Mux", "3412", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 23 Data Mux", "3421", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 23 Data Mux", "4123", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 23 Data Mux", "4132", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 23 Data Mux", "4213", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 23 Data Mux", "4231", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 23 Data Mux", "4312", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 23 Data Mux", "4321", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 23 Data Mux", NULL, "I2S1_2"},
+
+       {"TDM2 slot 45 Data Mux", "1234", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 45 Data Mux", "1243", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 45 Data Mux", "1324", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 45 Data Mux", "1342", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 45 Data Mux", "1432", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 45 Data Mux", "1423", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 45 Data Mux", "2134", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 45 Data Mux", "2143", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 45 Data Mux", "2314", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 45 Data Mux", "2341", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 45 Data Mux", "2431", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 45 Data Mux", "2413", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 45 Data Mux", "3124", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 45 Data Mux", "3142", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 45 Data Mux", "3214", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 45 Data Mux", "3241", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 45 Data Mux", "3412", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 45 Data Mux", "3421", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 45 Data Mux", "4123", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 45 Data Mux", "4132", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 45 Data Mux", "4213", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 45 Data Mux", "4231", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 45 Data Mux", "4312", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 45 Data Mux", "4321", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 45 Data Mux", NULL, "I2S1_2"},
+
+       {"TDM2 slot 67 Data Mux", "1234", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 67 Data Mux", "1243", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 67 Data Mux", "1324", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 67 Data Mux", "1342", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 67 Data Mux", "1432", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 67 Data Mux", "1423", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 67 Data Mux", "2134", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 67 Data Mux", "2143", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 67 Data Mux", "2314", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 67 Data Mux", "2341", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 67 Data Mux", "2431", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 67 Data Mux", "2413", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 67 Data Mux", "3124", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 67 Data Mux", "3142", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 67 Data Mux", "3214", "IF1_2_ADC4 Mux"},
+       {"TDM2 slot 67 Data Mux", "3241", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 67 Data Mux", "3412", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 67 Data Mux", "3421", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 67 Data Mux", "4123", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 67 Data Mux", "4132", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 67 Data Mux", "4213", "IF1_2_ADC3 Mux"},
+       {"TDM2 slot 67 Data Mux", "4231", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 67 Data Mux", "4312", "IF1_2_ADC2 Mux"},
+       {"TDM2 slot 67 Data Mux", "4321", "IF1_2_ADC1 Mux"},
+       {"TDM2 slot 67 Data Mux", NULL, "I2S1_2"},
+
+       {"IF1_1 0 ADC Swap Mux", "L/R", "TDM1 slot 01 Data Mux"},
+       {"IF1_1 0 ADC Swap Mux", "L/L", "TDM1 slot 01 Data Mux"},
+       {"IF1_1 1 ADC Swap Mux", "R/L", "TDM1 slot 01 Data Mux"},
+       {"IF1_1 1 ADC Swap Mux", "R/R", "TDM1 slot 01 Data Mux"},
+       {"IF1_1 2 ADC Swap Mux", "L/R", "TDM1 slot 23 Data Mux"},
+       {"IF1_1 2 ADC Swap Mux", "R/L", "TDM1 slot 23 Data Mux"},
+       {"IF1_1 3 ADC Swap Mux", "L/L", "TDM1 slot 23 Data Mux"},
+       {"IF1_1 3 ADC Swap Mux", "R/R", "TDM1 slot 23 Data Mux"},
+       {"IF1_1 4 ADC Swap Mux", "L/R", "TDM1 slot 45 Data Mux"},
+       {"IF1_1 4 ADC Swap Mux", "R/L", "TDM1 slot 45 Data Mux"},
+       {"IF1_1 5 ADC Swap Mux", "L/L", "TDM1 slot 45 Data Mux"},
+       {"IF1_1 5 ADC Swap Mux", "R/R", "TDM1 slot 45 Data Mux"},
+       {"IF1_1 6 ADC Swap Mux", "L/R", "TDM1 slot 67 Data Mux"},
+       {"IF1_1 6 ADC Swap Mux", "R/L", "TDM1 slot 67 Data Mux"},
+       {"IF1_1 7 ADC Swap Mux", "L/L", "TDM1 slot 67 Data Mux"},
+       {"IF1_1 7 ADC Swap Mux", "R/R", "TDM1 slot 67 Data Mux"},
+       {"IF1_2 0 ADC Swap Mux", "L/R", "TDM2 slot 01 Data Mux"},
+       {"IF1_2 0 ADC Swap Mux", "R/L", "TDM2 slot 01 Data Mux"},
+       {"IF1_2 1 ADC Swap Mux", "L/L", "TDM2 slot 01 Data Mux"},
+       {"IF1_2 1 ADC Swap Mux", "R/R", "TDM2 slot 01 Data Mux"},
+       {"IF1_2 2 ADC Swap Mux", "L/R", "TDM2 slot 23 Data Mux"},
+       {"IF1_2 2 ADC Swap Mux", "R/L", "TDM2 slot 23 Data Mux"},
+       {"IF1_2 3 ADC Swap Mux", "L/L", "TDM2 slot 23 Data Mux"},
+       {"IF1_2 3 ADC Swap Mux", "R/R", "TDM2 slot 23 Data Mux"},
+       {"IF1_2 4 ADC Swap Mux", "L/R", "TDM2 slot 45 Data Mux"},
+       {"IF1_2 4 ADC Swap Mux", "R/L", "TDM2 slot 45 Data Mux"},
+       {"IF1_2 5 ADC Swap Mux", "L/L", "TDM2 slot 45 Data Mux"},
+       {"IF1_2 5 ADC Swap Mux", "R/R", "TDM2 slot 45 Data Mux"},
+       {"IF1_2 6 ADC Swap Mux", "L/R", "TDM2 slot 67 Data Mux"},
+       {"IF1_2 6 ADC Swap Mux", "R/L", "TDM2 slot 67 Data Mux"},
+       {"IF1_2 7 ADC Swap Mux", "L/L", "TDM2 slot 67 Data Mux"},
+       {"IF1_2 7 ADC Swap Mux", "R/R", "TDM2 slot 67 Data Mux"},
+
+       {"IF2_1 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+       {"IF2_1 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+       {"IF2_1 ADC Mux", "MONO ADC", "Mono ADC MIX"},
+       {"IF2_1 ADC Mux", "IF1 DAC1", "IF1 DAC1"},
+       {"IF2_1 ADC Mux", "IF1 DAC2", "IF1 DAC2"},
+       {"IF2_1 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"},
+       {"IF2_1 ADC Mux", "IF3 DAC", "IF3 DAC"},
+       {"IF2_1 ADC Mux", "DAC1 MIX", "DAC1 MIX"},
+       {"IF2_1 ADC", NULL, "IF2_1 ADC Mux"},
+       {"IF2_1 ADC", NULL, "I2S2_1"},
+
+       {"IF2_2 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+       {"IF2_2 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+       {"IF2_2 ADC Mux", "MONO ADC", "Mono ADC MIX"},
+       {"IF2_2 ADC Mux", "IF1 DAC1", "IF1 DAC1"},
+       {"IF2_2 ADC Mux", "IF1 DAC2", "IF1 DAC2"},
+       {"IF2_2 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"},
+       {"IF2_2 ADC Mux", "IF3 DAC", "IF3 DAC"},
+       {"IF2_2 ADC Mux", "DAC1 MIX", "DAC1 MIX"},
+       {"IF2_2 ADC", NULL, "IF2_2 ADC Mux"},
+       {"IF2_2 ADC", NULL, "I2S2_2"},
+
+       {"IF3 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"},
+       {"IF3 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"},
+       {"IF3 ADC Mux", "MONO ADC", "Mono ADC MIX"},
+       {"IF3 ADC Mux", "IF1 DAC1", "IF1 DAC1"},
+       {"IF3 ADC Mux", "IF1 DAC2", "IF1 DAC2"},
+       {"IF3 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"},
+       {"IF3 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"},
+       {"IF3 ADC Mux", "DAC1 MIX", "DAC1 MIX"},
+       {"IF3 ADC", NULL, "IF3 ADC Mux"},
+       {"IF3 ADC", NULL, "I2S3"},
+
+       {"AIF1_1TX slot 0", NULL, "IF1_1 0 ADC Swap Mux"},
+       {"AIF1_1TX slot 1", NULL, "IF1_1 1 ADC Swap Mux"},
+       {"AIF1_1TX slot 2", NULL, "IF1_1 2 ADC Swap Mux"},
+       {"AIF1_1TX slot 3", NULL, "IF1_1 3 ADC Swap Mux"},
+       {"AIF1_1TX slot 4", NULL, "IF1_1 4 ADC Swap Mux"},
+       {"AIF1_1TX slot 5", NULL, "IF1_1 5 ADC Swap Mux"},
+       {"AIF1_1TX slot 6", NULL, "IF1_1 6 ADC Swap Mux"},
+       {"AIF1_1TX slot 7", NULL, "IF1_1 7 ADC Swap Mux"},
+       {"AIF1_2TX slot 0", NULL, "IF1_2 0 ADC Swap Mux"},
+       {"AIF1_2TX slot 1", NULL, "IF1_2 1 ADC Swap Mux"},
+       {"AIF1_2TX slot 2", NULL, "IF1_2 2 ADC Swap Mux"},
+       {"AIF1_2TX slot 3", NULL, "IF1_2 3 ADC Swap Mux"},
+       {"AIF1_2TX slot 4", NULL, "IF1_2 4 ADC Swap Mux"},
+       {"AIF1_2TX slot 5", NULL, "IF1_2 5 ADC Swap Mux"},
+       {"AIF1_2TX slot 6", NULL, "IF1_2 6 ADC Swap Mux"},
+       {"AIF1_2TX slot 7", NULL, "IF1_2 7 ADC Swap Mux"},
+       {"IF2_1 ADC Swap Mux", "L/R", "IF2_1 ADC"},
+       {"IF2_1 ADC Swap Mux", "R/L", "IF2_1 ADC"},
+       {"IF2_1 ADC Swap Mux", "L/L", "IF2_1 ADC"},
+       {"IF2_1 ADC Swap Mux", "R/R", "IF2_1 ADC"},
+       {"AIF2_1TX", NULL, "IF2_1 ADC Swap Mux"},
+       {"IF2_2 ADC Swap Mux", "L/R", "IF2_2 ADC"},
+       {"IF2_2 ADC Swap Mux", "R/L", "IF2_2 ADC"},
+       {"IF2_2 ADC Swap Mux", "L/L", "IF2_2 ADC"},
+       {"IF2_2 ADC Swap Mux", "R/R", "IF2_2 ADC"},
+       {"AIF2_2TX", NULL, "IF2_2 ADC Swap Mux"},
+       {"IF3 ADC Swap Mux", "L/R", "IF3 ADC"},
+       {"IF3 ADC Swap Mux", "R/L", "IF3 ADC"},
+       {"IF3 ADC Swap Mux", "L/L", "IF3 ADC"},
+       {"IF3 ADC Swap Mux", "R/R", "IF3 ADC"},
+       {"AIF3TX", NULL, "IF3 ADC Swap Mux"},
+
+       {"IF1 DAC1", NULL, "AIF1RX"},
+       {"IF1 DAC2", NULL, "AIF1RX"},
+       {"IF1 DAC3", NULL, "AIF1RX"},
+       {"IF2_1 DAC Swap Mux", "L/R", "AIF2_1RX"},
+       {"IF2_1 DAC Swap Mux", "R/L", "AIF2_1RX"},
+       {"IF2_1 DAC Swap Mux", "L/L", "AIF2_1RX"},
+       {"IF2_1 DAC Swap Mux", "R/R", "AIF2_1RX"},
+       {"IF2_2 DAC Swap Mux", "L/R", "AIF2_2RX"},
+       {"IF2_2 DAC Swap Mux", "R/L", "AIF2_2RX"},
+       {"IF2_2 DAC Swap Mux", "L/L", "AIF2_2RX"},
+       {"IF2_2 DAC Swap Mux", "R/R", "AIF2_2RX"},
+       {"IF2_1 DAC", NULL, "IF2_1 DAC Swap Mux"},
+       {"IF2_2 DAC", NULL, "IF2_2 DAC Swap Mux"},
+       {"IF3 DAC Swap Mux", "L/R", "AIF3RX"},
+       {"IF3 DAC Swap Mux", "R/L", "AIF3RX"},
+       {"IF3 DAC Swap Mux", "L/L", "AIF3RX"},
+       {"IF3 DAC Swap Mux", "R/R", "AIF3RX"},
+       {"IF3 DAC", NULL, "IF3 DAC Swap Mux"},
+
+       {"IF1 DAC1", NULL, "I2S1_1"},
+       {"IF1 DAC2", NULL, "I2S1_1"},
+       {"IF1 DAC3", NULL, "I2S1_1"},
+       {"IF2_1 DAC", NULL, "I2S2_1"},
+       {"IF2_2 DAC", NULL, "I2S2_2"},
+       {"IF3 DAC", NULL, "I2S3"},
+
+       {"IF1 DAC1 L", NULL, "IF1 DAC1"},
+       {"IF1 DAC1 R", NULL, "IF1 DAC1"},
+       {"IF1 DAC2 L", NULL, "IF1 DAC2"},
+       {"IF1 DAC2 R", NULL, "IF1 DAC2"},
+       {"IF1 DAC3 L", NULL, "IF1 DAC3"},
+       {"IF1 DAC3 R", NULL, "IF1 DAC3"},
+       {"IF2_1 DAC L", NULL, "IF2_1 DAC"},
+       {"IF2_1 DAC R", NULL, "IF2_1 DAC"},
+       {"IF2_2 DAC L", NULL, "IF2_2 DAC"},
+       {"IF2_2 DAC R", NULL, "IF2_2 DAC"},
+       {"IF3 DAC L", NULL, "IF3 DAC"},
+       {"IF3 DAC R", NULL, "IF3 DAC"},
+
+       {"DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L"},
+       {"DAC L1 Mux", "IF2_1 DAC", "IF2_1 DAC L"},
+       {"DAC L1 Mux", "IF2_2 DAC", "IF2_2 DAC L"},
+       {"DAC L1 Mux", "IF3 DAC", "IF3 DAC L"},
+       {"DAC L1 Mux", NULL, "DAC Stereo1 Filter"},
+
+       {"DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R"},
+       {"DAC R1 Mux", "IF2_1 DAC", "IF2_1 DAC R"},
+       {"DAC R1 Mux", "IF2_2 DAC", "IF2_2 DAC R"},
+       {"DAC R1 Mux", "IF3 DAC", "IF3 DAC R"},
+       {"DAC R1 Mux", NULL, "DAC Stereo1 Filter"},
+
+       {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+       {"DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux"},
+       {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+       {"DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux"},
+
+       {"DAC1 MIX", NULL, "DAC1 MIXL"},
+       {"DAC1 MIX", NULL, "DAC1 MIXR"},
+
+       {"DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L"},
+       {"DAC L2 Mux", "IF2_1 DAC", "IF2_1 DAC L"},
+       {"DAC L2 Mux", "IF2_2 DAC", "IF2_2 DAC L"},
+       {"DAC L2 Mux", "IF3 DAC", "IF3 DAC L"},
+       {"DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL"},
+       {"DAC L2 Mux", NULL, "DAC Mono Left Filter"},
+
+       {"DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R"},
+       {"DAC R2 Mux", "IF2_1 DAC", "IF2_1 DAC R"},
+       {"DAC R2 Mux", "IF2_2 DAC", "IF2_2 DAC R"},
+       {"DAC R2 Mux", "IF3 DAC", "IF3 DAC R"},
+       {"DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR"},
+       {"DAC R2 Mux", NULL, "DAC Mono Right Filter"},
+
+       {"DAC L3 Mux", "IF1 DAC2", "IF1 DAC2 L"},
+       {"DAC L3 Mux", "IF2_1 DAC", "IF2_1 DAC L"},
+       {"DAC L3 Mux", "IF2_2 DAC", "IF2_2 DAC L"},
+       {"DAC L3 Mux", "IF3 DAC", "IF3 DAC L"},
+       {"DAC L3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXL"},
+       {"DAC L3 Mux", NULL, "DAC Stereo2 Filter"},
+
+       {"DAC R3 Mux", "IF1 DAC2", "IF1 DAC2 R"},
+       {"DAC R3 Mux", "IF2_1 DAC", "IF2_1 DAC R"},
+       {"DAC R3 Mux", "IF2_2 DAC", "IF2_2 DAC R"},
+       {"DAC R3 Mux", "IF3 DAC", "IF3 DAC R"},
+       {"DAC R3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXR"},
+       {"DAC R3 Mux", NULL, "DAC Stereo2 Filter"},
+
+       {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+       {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+       {"Stereo1 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Stereo1 DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+
+       {"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+       {"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+       {"Stereo1 DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Stereo1 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+
+       {"Stereo2 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+       {"Stereo2 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Stereo2 DAC MIXL", "DAC L3 Switch", "DAC L3 Mux"},
+
+       {"Stereo2 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+       {"Stereo2 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Stereo2 DAC MIXR", "DAC R3 Switch", "DAC R3 Mux"},
+
+       {"Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+       {"Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+       {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+       {"Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+       {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+
+       {"DAC MIXL", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+       {"DAC MIXL", "Stereo2 DAC Mixer", "Stereo2 DAC MIXL"},
+       {"DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL"},
+       {"DAC MIXR", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+       {"DAC MIXR", "Stereo2 DAC Mixer", "Stereo2 DAC MIXR"},
+       {"DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+       {"DAC L1 Source", "DAC1", "DAC1 MIXL"},
+       {"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+       {"DAC L1 Source", "DMIC1", "DMIC L1"},
+       {"DAC R1 Source", "DAC1", "DAC1 MIXR"},
+       {"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+       {"DAC R1 Source", "DMIC1", "DMIC R1"},
+
+       {"DAC L2 Source", "DAC2", "DAC L2 Mux"},
+       {"DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL"},
+       {"DAC L2 Source", NULL, "DAC L2 Power"},
+       {"DAC R2 Source", "DAC2", "DAC R2 Mux"},
+       {"DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR"},
+       {"DAC R2 Source", NULL, "DAC R2 Power"},
+
+       {"DAC L1", NULL, "DAC L1 Source"},
+       {"DAC R1", NULL, "DAC R1 Source"},
+       {"DAC L2", NULL, "DAC L2 Source"},
+       {"DAC R2", NULL, "DAC R2 Source"},
+
+       {"DAC L1", NULL, "DAC 1 Clock"},
+       {"DAC R1", NULL, "DAC 1 Clock"},
+       {"DAC L2", NULL, "DAC 2 Clock"},
+       {"DAC R2", NULL, "DAC 2 Clock"},
+
+       {"MONOVOL MIX", "DAC L2 Switch", "DAC L2"},
+       {"MONOVOL MIX", "RECMIX2L Switch", "RECMIX2L"},
+       {"MONOVOL MIX", "BST1 Switch", "BST1"},
+       {"MONOVOL MIX", "BST2 Switch", "BST2"},
+       {"MONOVOL MIX", "BST3 Switch", "BST3"},
+
+       {"OUT MIXL", "DAC L2 Switch", "DAC L2"},
+       {"OUT MIXL", "INL Switch", "INL VOL"},
+       {"OUT MIXL", "BST1 Switch", "BST1"},
+       {"OUT MIXL", "BST2 Switch", "BST2"},
+       {"OUT MIXL", "BST3 Switch", "BST3"},
+       {"OUT MIXR", "DAC R2 Switch", "DAC R2"},
+       {"OUT MIXR", "INR Switch", "INR VOL"},
+       {"OUT MIXR", "BST2 Switch", "BST2"},
+       {"OUT MIXR", "BST3 Switch", "BST3"},
+       {"OUT MIXR", "BST4 Switch", "BST4"},
+
+       {"MONOVOL", "Switch", "MONOVOL MIX"},
+       {"Mono MIX", "DAC L2 Switch", "DAC L2"},
+       {"Mono MIX", "MONOVOL Switch", "MONOVOL"},
+       {"Mono Amp", NULL, "Mono MIX"},
+       {"Mono Amp", NULL, "Vref2"},
+       {"Mono Amp", NULL, "CLKDET SYS"},
+       {"Mono Amp", NULL, "CLKDET MONO"},
+       {"Mono Playback", "Switch", "Mono Amp"},
+       {"MONOOUT", NULL, "Mono Playback"},
+
+       {"HP Amp", NULL, "DAC L1"},
+       {"HP Amp", NULL, "DAC R1"},
+       {"HP Amp", NULL, "Charge Pump"},
+       {"HP Amp", NULL, "CLKDET SYS"},
+       {"HP Amp", NULL, "CLKDET HP"},
+       {"HP Amp", NULL, "CBJ Power"},
+       {"HP Amp", NULL, "Vref2"},
+       {"HPO Playback", "Switch", "HP Amp"},
+       {"HPOL", NULL, "HPO Playback"},
+       {"HPOR", NULL, "HPO Playback"},
+
+       {"OUTVOL L", "Switch", "OUT MIXL"},
+       {"OUTVOL R", "Switch", "OUT MIXR"},
+       {"LOUT L MIX", "DAC L2 Switch", "DAC L2"},
+       {"LOUT L MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"LOUT R MIX", "DAC R2 Switch", "DAC R2"},
+       {"LOUT R MIX", "OUTVOL R Switch", "OUTVOL R"},
+       {"LOUT Amp", NULL, "LOUT L MIX"},
+       {"LOUT Amp", NULL, "LOUT R MIX"},
+       {"LOUT Amp", NULL, "Vref1"},
+       {"LOUT Amp", NULL, "Vref2"},
+       {"LOUT Amp", NULL, "CLKDET SYS"},
+       {"LOUT Amp", NULL, "CLKDET LOUT"},
+       {"LOUT L Playback", "Switch", "LOUT Amp"},
+       {"LOUT R Playback", "Switch", "LOUT Amp"},
+       {"LOUTL", NULL, "LOUT L Playback"},
+       {"LOUTR", NULL, "LOUT R Playback"},
+
+       {"PDM L Mux", "Mono DAC", "Mono DAC MIXL"},
+       {"PDM L Mux", "Stereo1 DAC", "Stereo1 DAC MIXL"},
+       {"PDM L Mux", "Stereo2 DAC", "Stereo2 DAC MIXL"},
+       {"PDM L Mux", NULL, "PDM Power"},
+       {"PDM R Mux", "Mono DAC", "Mono DAC MIXR"},
+       {"PDM R Mux", "Stereo1 DAC", "Stereo1 DAC MIXR"},
+       {"PDM R Mux", "Stereo2 DAC", "Stereo2 DAC MIXR"},
+       {"PDM R Mux", NULL, "PDM Power"},
+       {"PDM L Playback", "Switch", "PDM L Mux"},
+       {"PDM R Playback", "Switch", "PDM R Mux"},
+       {"PDML", NULL, "PDM L Playback"},
+       {"PDMR", NULL, "PDM R Playback"},
+};
+
+static int rt5665_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val_len = 0, val_clk, mask_clk, val_bits = 0x0100;
+       int pre_div, frame_size;
+
+       rt5665->lrck[dai->id] = params_rate(params);
+       pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]);
+       if (pre_div < 0) {
+               dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+                       rt5665->lrck[dai->id], dai->id);
+               return -EINVAL;
+       }
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0) {
+               dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+                               rt5665->lrck[dai->id], pre_div, dai->id);
+
+       switch (params_width(params)) {
+       case 16:
+               val_bits = 0x0100;
+               break;
+       case 20:
+               val_len |= RT5665_I2S_DL_20;
+               val_bits = 0x1300;
+               break;
+       case 24:
+               val_len |= RT5665_I2S_DL_24;
+               val_bits = 0x2500;
+               break;
+       case 8:
+               val_len |= RT5665_I2S_DL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5665_AIF1_1:
+       case RT5665_AIF1_2:
+               mask_clk = RT5665_I2S_PD1_MASK;
+               val_clk = pre_div << RT5665_I2S_PD1_SFT;
+               snd_soc_update_bits(codec, RT5665_I2S1_SDP,
+                       RT5665_I2S_DL_MASK, val_len);
+               break;
+       case RT5665_AIF2_1:
+       case RT5665_AIF2_2:
+               mask_clk = RT5665_I2S_PD2_MASK;
+               val_clk = pre_div << RT5665_I2S_PD2_SFT;
+               snd_soc_update_bits(codec, RT5665_I2S2_SDP,
+                       RT5665_I2S_DL_MASK, val_len);
+               break;
+       case RT5665_AIF3:
+               mask_clk = RT5665_I2S_PD3_MASK;
+               val_clk = pre_div << RT5665_I2S_PD3_SFT;
+               snd_soc_update_bits(codec, RT5665_I2S3_SDP,
+                       RT5665_I2S_DL_MASK, val_len);
+               break;
+       default:
+               dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, mask_clk, val_clk);
+       snd_soc_update_bits(codec, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits);
+
+       switch (rt5665->lrck[dai->id]) {
+       case 192000:
+               snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+                       RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
+                       RT5665_DAC_OSR_32 | RT5665_ADC_OSR_32);
+               break;
+       case 96000:
+               snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+                       RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
+                       RT5665_DAC_OSR_64 | RT5665_ADC_OSR_64);
+               break;
+       default:
+               snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+                       RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK,
+                       RT5665_DAC_OSR_128 | RT5665_ADC_OSR_128);
+               break;
+       }
+
+       return 0;
+}
+
+static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5665->master[dai->id] = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               reg_val |= RT5665_I2S_MS_S;
+               rt5665->master[dai->id] = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg_val |= RT5665_I2S_BP_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg_val |= RT5665_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               reg_val |= RT5665_I2S_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               reg_val |= RT5665_I2S_DF_PCM_B;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (dai->id) {
+       case RT5665_AIF1_1:
+       case RT5665_AIF1_2:
+               snd_soc_update_bits(codec, RT5665_I2S1_SDP,
+                       RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
+                       RT5665_I2S_DF_MASK, reg_val);
+               break;
+       case RT5665_AIF2_1:
+       case RT5665_AIF2_2:
+               snd_soc_update_bits(codec, RT5665_I2S2_SDP,
+                       RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
+                       RT5665_I2S_DF_MASK, reg_val);
+               break;
+       case RT5665_AIF3:
+               snd_soc_update_bits(codec, RT5665_I2S3_SDP,
+                       RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK |
+                       RT5665_I2S_DF_MASK, reg_val);
+               break;
+       default:
+               dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src)
+               return 0;
+
+       switch (clk_id) {
+       case RT5665_SCLK_S_MCLK:
+               reg_val |= RT5665_SCLK_SRC_MCLK;
+               break;
+       case RT5665_SCLK_S_PLL1:
+               reg_val |= RT5665_SCLK_SRC_PLL1;
+               break;
+       case RT5665_SCLK_S_RCCLK:
+               reg_val |= RT5665_SCLK_SRC_RCCLK;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, RT5665_GLB_CLK,
+               RT5665_SCLK_SRC_MASK, reg_val);
+       rt5665->sysclk = freq;
+       rt5665->sysclk_src = clk_id;
+
+       dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+
+       return 0;
+}
+
+static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source,
+                       unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+       struct rl6231_pll_code pll_code;
+       int ret;
+
+       if (Source == rt5665->pll_src && freq_in == rt5665->pll_in &&
+           freq_out == rt5665->pll_out)
+               return 0;
+
+       if (!freq_in || !freq_out) {
+               dev_dbg(codec->dev, "PLL disabled\n");
+
+               rt5665->pll_in = 0;
+               rt5665->pll_out = 0;
+               snd_soc_update_bits(codec, RT5665_GLB_CLK,
+                       RT5665_SCLK_SRC_MASK, RT5665_SCLK_SRC_MCLK);
+               return 0;
+       }
+
+       switch (Source) {
+       case RT5665_PLL1_S_MCLK:
+               snd_soc_update_bits(codec, RT5665_GLB_CLK,
+                       RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK);
+               break;
+       case RT5665_PLL1_S_BCLK1:
+               snd_soc_update_bits(codec, RT5665_GLB_CLK,
+                               RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK1);
+               break;
+       case RT5665_PLL1_S_BCLK2:
+               snd_soc_update_bits(codec, RT5665_GLB_CLK,
+                               RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK2);
+               break;
+       case RT5665_PLL1_S_BCLK3:
+               snd_soc_update_bits(codec, RT5665_GLB_CLK,
+                               RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3);
+               break;
+       default:
+               dev_err(codec->dev, "Unknown PLL Source %d\n", Source);
+               return -EINVAL;
+       }
+
+       ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n",
+               pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+               pll_code.n_code, pll_code.k_code);
+
+       snd_soc_write(codec, RT5665_PLL_CTRL_1,
+               pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code);
+       snd_soc_write(codec, RT5665_PLL_CTRL_2,
+               (pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT |
+               pll_code.m_bp << RT5665_PLL_M_BP_SFT);
+
+       rt5665->pll_in = freq_in;
+       rt5665->pll_out = freq_out;
+       rt5665->pll_src = Source;
+
+       return 0;
+}
+
+static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+                       unsigned int rx_mask, int slots, int slot_width)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       unsigned int val = 0;
+
+       if (rx_mask || tx_mask)
+               val |= RT5665_I2S1_MODE_TDM;
+
+       switch (slots) {
+       case 4:
+               val |= RT5665_TDM_IN_CH_4;
+               val |= RT5665_TDM_OUT_CH_4;
+               break;
+       case 6:
+               val |= RT5665_TDM_IN_CH_6;
+               val |= RT5665_TDM_OUT_CH_6;
+               break;
+       case 8:
+               val |= RT5665_TDM_IN_CH_8;
+               val |= RT5665_TDM_OUT_CH_8;
+               break;
+       case 2:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (slot_width) {
+       case 20:
+               val |= RT5665_TDM_IN_LEN_20;
+               val |= RT5665_TDM_OUT_LEN_20;
+               break;
+       case 24:
+               val |= RT5665_TDM_IN_LEN_24;
+               val |= RT5665_TDM_OUT_LEN_24;
+               break;
+       case 32:
+               val |= RT5665_TDM_IN_LEN_32;
+               val |= RT5665_TDM_OUT_LEN_32;
+               break;
+       case 16:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, RT5665_TDM_CTRL_1,
+               RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK |
+               RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK |
+               RT5665_TDM_OUT_LEN_MASK, val);
+
+       return 0;
+}
+
+static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio);
+
+       rt5665->bclk[dai->id] = ratio;
+
+       if (ratio == 64) {
+               switch (dai->id) {
+               case RT5665_AIF2_1:
+               case RT5665_AIF2_2:
+                       snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+                               RT5665_I2S_BCLK_MS2_MASK,
+                               RT5665_I2S_BCLK_MS2_64);
+                       break;
+               case RT5665_AIF3:
+                       snd_soc_update_bits(codec, RT5665_ADDA_CLK_1,
+                               RT5665_I2S_BCLK_MS3_MASK,
+                               RT5665_I2S_BCLK_MS3_64);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int rt5665_set_bias_level(struct snd_soc_codec *codec,
+                       enum snd_soc_bias_level level)
+{
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC,
+                       RT5665_DIG_GATE_CTRL, RT5665_DIG_GATE_CTRL);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1,
+                       RT5665_PWR_LDO, RT5665_PWR_LDO);
+               regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1,
+                       RT5665_PWR_MB, RT5665_PWR_MB);
+               regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC,
+                       RT5665_DIG_GATE_CTRL, 0);
+               break;
+       case SND_SOC_BIAS_OFF:
+               regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1,
+                       RT5665_PWR_LDO, 0);
+               regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1,
+                       RT5665_PWR_MB, 0);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int rt5665_probe(struct snd_soc_codec *codec)
+{
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+
+       rt5665->codec = codec;
+
+       schedule_delayed_work(&rt5665->calibrate_work, msecs_to_jiffies(100));
+
+       return 0;
+}
+
+static int rt5665_remove(struct snd_soc_codec *codec)
+{
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+
+       regmap_write(rt5665->regmap, RT5665_RESET, 0);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5665_suspend(struct snd_soc_codec *codec)
+{
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5665->regmap, true);
+       regcache_mark_dirty(rt5665->regmap);
+       return 0;
+}
+
+static int rt5665_resume(struct snd_soc_codec *codec)
+{
+       struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_cache_only(rt5665->regmap, false);
+       regcache_sync(rt5665->regmap);
+
+       return 0;
+}
+#else
+#define rt5665_suspend NULL
+#define rt5665_resume NULL
+#endif
+
+#define RT5665_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5665_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5665_aif_dai_ops = {
+       .hw_params = rt5665_hw_params,
+       .set_fmt = rt5665_set_dai_fmt,
+       .set_sysclk = rt5665_set_dai_sysclk,
+       .set_tdm_slot = rt5665_set_tdm_slot,
+       .set_pll = rt5665_set_dai_pll,
+       .set_bclk_ratio = rt5665_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5665_dai[] = {
+       {
+               .name = "rt5665-aif1_1",
+               .id = RT5665_AIF1_1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1_1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .ops = &rt5665_aif_dai_ops,
+       },
+       {
+               .name = "rt5665-aif1_2",
+               .id = RT5665_AIF1_2,
+               .capture = {
+                       .stream_name = "AIF1_2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .ops = &rt5665_aif_dai_ops,
+       },
+       {
+               .name = "rt5665-aif2_1",
+               .id = RT5665_AIF2_1,
+               .playback = {
+                       .stream_name = "AIF2_1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF2_1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .ops = &rt5665_aif_dai_ops,
+       },
+       {
+               .name = "rt5665-aif2_2",
+               .id = RT5665_AIF2_2,
+               .playback = {
+                       .stream_name = "AIF2_2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF2_2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .ops = &rt5665_aif_dai_ops,
+       },
+       {
+               .name = "rt5665-aif3",
+               .id = RT5665_AIF3,
+               .playback = {
+                       .stream_name = "AIF3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF3 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5665_STEREO_RATES,
+                       .formats = RT5665_FORMATS,
+               },
+               .ops = &rt5665_aif_dai_ops,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5665 = {
+       .probe = rt5665_probe,
+       .remove = rt5665_remove,
+       .suspend = rt5665_suspend,
+       .resume = rt5665_resume,
+       .set_bias_level = rt5665_set_bias_level,
+       .idle_bias_off = true,
+       .component_driver = {
+               .controls = rt5665_snd_controls,
+               .num_controls = ARRAY_SIZE(rt5665_snd_controls),
+               .dapm_widgets = rt5665_dapm_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(rt5665_dapm_widgets),
+               .dapm_routes = rt5665_dapm_routes,
+               .num_dapm_routes = ARRAY_SIZE(rt5665_dapm_routes),
+       }
+};
+
+
+static const struct regmap_config rt5665_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+       .max_register = 0x0400,
+       .volatile_reg = rt5665_volatile_register,
+       .readable_reg = rt5665_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5665_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5665_reg),
+       .use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5665_i2c_id[] = {
+       {"rt5665", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, rt5665_i2c_id);
+
+static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev)
+{
+       rt5665->pdata.in1_diff = of_property_read_bool(dev->of_node,
+                                       "realtek,in1-differential");
+       rt5665->pdata.in2_diff = of_property_read_bool(dev->of_node,
+                                       "realtek,in2-differential");
+       rt5665->pdata.in3_diff = of_property_read_bool(dev->of_node,
+                                       "realtek,in3-differential");
+       rt5665->pdata.in4_diff = of_property_read_bool(dev->of_node,
+                                       "realtek,in4-differential");
+
+       of_property_read_u32(dev->of_node, "realtek,dmic1-data-pin",
+               &rt5665->pdata.dmic1_data_pin);
+       of_property_read_u32(dev->of_node, "realtek,dmic2-data-pin",
+               &rt5665->pdata.dmic2_data_pin);
+       of_property_read_u32(dev->of_node, "realtek,jd-src",
+               &rt5665->pdata.jd_src);
+
+       rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
+               "realtek,ldo1-en-gpios", 0);
+
+       return 0;
+}
+
+static void rt5665_calibrate(struct rt5665_priv *rt5665)
+{
+       int value, count;
+
+       mutex_lock(&rt5665->calibrate_mutex);
+
+       regcache_cache_bypass(rt5665->regmap, true);
+
+       regmap_write(rt5665->regmap, RT5665_RESET, 0);
+       regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
+       regmap_write(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, 0x0c26);
+       regmap_write(rt5665->regmap, RT5665_MONOMIX_IN_GAIN, 0x021f);
+       regmap_write(rt5665->regmap, RT5665_MONO_OUT, 0x480a);
+       regmap_write(rt5665->regmap, RT5665_PWR_MIXER, 0x083f);
+       regmap_write(rt5665->regmap, RT5665_PWR_DIG_1, 0x0180);
+       regmap_write(rt5665->regmap, RT5665_EJD_CTRL_1, 0x4040);
+       regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0000);
+       regmap_write(rt5665->regmap, RT5665_DIG_MISC, 0x0001);
+       regmap_write(rt5665->regmap, RT5665_MICBIAS_2, 0x0380);
+       regmap_write(rt5665->regmap, RT5665_GLB_CLK, 0x8000);
+       regmap_write(rt5665->regmap, RT5665_ADDA_CLK_1, 0x1000);
+       regmap_write(rt5665->regmap, RT5665_CHOP_DAC, 0x3030);
+       regmap_write(rt5665->regmap, RT5665_CALIB_ADC_CTRL, 0x3c05);
+       regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xaa3e);
+       usleep_range(15000, 20000);
+       regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xfe7e);
+       regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_2, 0x0321);
+
+       regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_1, 0xfc00);
+       count = 0;
+       while (true) {
+               regmap_read(rt5665->regmap, RT5665_HP_CALIB_STA_1, &value);
+               if (value & 0x8000)
+                       usleep_range(10000, 10005);
+               else
+                       break;
+
+               if (count > 60) {
+                       pr_err("HP Calibration Failure\n");
+                       regmap_write(rt5665->regmap, RT5665_RESET, 0);
+                       regcache_cache_bypass(rt5665->regmap, false);
+                       return;
+               }
+
+               count++;
+       }
+
+       regmap_write(rt5665->regmap, RT5665_MONO_AMP_CALIB_CTRL_1, 0x9e24);
+       count = 0;
+       while (true) {
+               regmap_read(rt5665->regmap, RT5665_MONO_AMP_CALIB_STA1, &value);
+               if (value & 0x8000)
+                       usleep_range(10000, 10005);
+               else
+                       break;
+
+               if (count > 60) {
+                       pr_err("MONO Calibration Failure\n");
+                       regmap_write(rt5665->regmap, RT5665_RESET, 0);
+                       regcache_cache_bypass(rt5665->regmap, false);
+                       return;
+               }
+
+               count++;
+       }
+
+       regmap_write(rt5665->regmap, RT5665_RESET, 0);
+       regcache_cache_bypass(rt5665->regmap, false);
+
+       regcache_mark_dirty(rt5665->regmap);
+       regcache_sync(rt5665->regmap);
+
+       regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
+       regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120);
+
+       mutex_unlock(&rt5665->calibrate_mutex);
+}
+
+static void rt5665_calibrate_handler(struct work_struct *work)
+{
+       struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv,
+               calibrate_work.work);
+
+       while (!rt5665->codec->component.card->instantiated) {
+               pr_debug("%s\n", __func__);
+               usleep_range(10000, 15000);
+       }
+
+       rt5665_calibrate(rt5665);
+}
+
+static int rt5665_i2c_probe(struct i2c_client *i2c,
+                   const struct i2c_device_id *id)
+{
+       struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev);
+       struct rt5665_priv *rt5665;
+       int i, ret;
+       unsigned int val;
+
+       rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv),
+               GFP_KERNEL);
+
+       if (rt5665 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, rt5665);
+
+       if (pdata)
+               rt5665->pdata = *pdata;
+       else
+               rt5665_parse_dt(rt5665, &i2c->dev);
+
+       for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++)
+               rt5665->supplies[i].supply = rt5665_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies),
+                                     rt5665->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies),
+                                   rt5665->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       if (gpio_is_valid(rt5665->pdata.ldo1_en)) {
+               if (devm_gpio_request(&i2c->dev, rt5665->pdata.ldo1_en,
+                       "rt5665"))
+                       dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+               else if (gpio_direction_output(rt5665->pdata.ldo1_en, 1))
+                       dev_err(&i2c->dev, "Fail gpio_direction gpio_ldo\n");
+       }
+
+       /* Sleep for 300 ms miniumum */
+       usleep_range(300000, 350000);
+
+       rt5665->regmap = devm_regmap_init_i2c(i2c, &rt5665_regmap);
+       if (IS_ERR(rt5665->regmap)) {
+               ret = PTR_ERR(rt5665->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       regmap_read(rt5665->regmap, RT5665_DEVICE_ID, &val);
+       if (val != DEVICE_ID) {
+               dev_err(&i2c->dev,
+                       "Device with ID register %x is not rt5665\n", val);
+               return -ENODEV;
+       }
+
+       regmap_read(rt5665->regmap, RT5665_RESET, &val);
+       switch (val) {
+       case 0x0:
+               rt5665->id = CODEC_5666;
+               break;
+       case 0x6:
+               rt5665->id = CODEC_5668;
+               break;
+       case 0x3:
+       default:
+               rt5665->id = CODEC_5665;
+               break;
+       }
+
+       regmap_write(rt5665->regmap, RT5665_RESET, 0);
+
+       /* line in diff mode*/
+       if (rt5665->pdata.in1_diff)
+               regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2,
+                       RT5665_IN1_DF_MASK, RT5665_IN1_DF_MASK);
+       if (rt5665->pdata.in2_diff)
+               regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2,
+                       RT5665_IN2_DF_MASK, RT5665_IN2_DF_MASK);
+       if (rt5665->pdata.in3_diff)
+               regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4,
+                       RT5665_IN3_DF_MASK, RT5665_IN3_DF_MASK);
+       if (rt5665->pdata.in4_diff)
+               regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4,
+                       RT5665_IN4_DF_MASK, RT5665_IN4_DF_MASK);
+
+       /* DMIC pin*/
+       if (rt5665->pdata.dmic1_data_pin != RT5665_DMIC1_NULL ||
+               rt5665->pdata.dmic2_data_pin != RT5665_DMIC2_NULL) {
+               regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2,
+                       RT5665_GP9_PIN_MASK, RT5665_GP9_PIN_DMIC1_SCL);
+               regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+                               RT5665_GP8_PIN_MASK, RT5665_GP8_PIN_DMIC2_SCL);
+               switch (rt5665->pdata.dmic1_data_pin) {
+               case RT5665_DMIC1_DATA_IN2N:
+                       regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1,
+                               RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_IN2N);
+                       break;
+
+               case RT5665_DMIC1_DATA_GPIO4:
+                       regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1,
+                               RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_GPIO4);
+                       regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+                               RT5665_GP4_PIN_MASK, RT5665_GP4_PIN_DMIC1_SDA);
+                       break;
+
+               default:
+                       dev_dbg(&i2c->dev, "no DMIC1\n");
+                       break;
+               }
+
+               switch (rt5665->pdata.dmic2_data_pin) {
+               case RT5665_DMIC2_DATA_IN2P:
+                       regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1,
+                               RT5665_DMIC_2_DP_MASK, RT5665_DMIC_2_DP_IN2P);
+                       break;
+
+               case RT5665_DMIC2_DATA_GPIO5:
+                       regmap_update_bits(rt5665->regmap,
+                               RT5665_DMIC_CTRL_1,
+                               RT5665_DMIC_2_DP_MASK,
+                               RT5665_DMIC_2_DP_GPIO5);
+                       regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1,
+                               RT5665_GP5_PIN_MASK, RT5665_GP5_PIN_DMIC2_SDA);
+                       break;
+
+               default:
+                       dev_dbg(&i2c->dev, "no DMIC2\n");
+                       break;
+
+               }
+       }
+
+       regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0002);
+       regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1,
+               0xf000 | RT5665_VREF_POW_MASK, 0xd000 | RT5665_VREF_POW_REG);
+       /* Work around for pow_pump */
+       regmap_update_bits(rt5665->regmap, RT5665_STO1_DAC_SIL_DET,
+               RT5665_DEB_STO_DAC_MASK, RT5665_DEB_80_MS);
+
+       regmap_update_bits(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1,
+               RT5665_PM_HP_MASK, RT5665_PM_HP_HV);
+
+       /* Set GPIO4,8 as input for combo jack */
+       if (rt5665->id == CODEC_5666) {
+               regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2,
+                       RT5665_GP4_PF_MASK, RT5665_GP4_PF_IN);
+               regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_3,
+                       RT5665_GP8_PF_MASK, RT5665_GP8_PF_IN);
+       }
+
+       /* Enhance performance*/
+       regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1,
+               RT5665_HP_DRIVER_MASK | RT5665_LDO1_DVO_MASK,
+               RT5665_HP_DRIVER_5X | RT5665_LDO1_DVO_09);
+
+       INIT_DELAYED_WORK(&rt5665->jack_detect_work,
+                               rt5665_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt5665->calibrate_work,
+                               rt5665_calibrate_handler);
+       INIT_DELAYED_WORK(&rt5665->jd_check_work,
+                               rt5665_jd_check_handler);
+
+       mutex_init(&rt5665->calibrate_mutex);
+
+       if (i2c->irq) {
+               ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+                       rt5665_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+                       | IRQF_ONESHOT, "rt5665", rt5665);
+               if (ret)
+                       dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+       }
+
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5665,
+                       rt5665_dai, ARRAY_SIZE(rt5665_dai));
+}
+
+static int rt5665_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+static void rt5665_i2c_shutdown(struct i2c_client *client)
+{
+       struct rt5665_priv *rt5665 = i2c_get_clientdata(client);
+
+       regmap_write(rt5665->regmap, RT5665_RESET, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5665_of_match[] = {
+       {.compatible = "realtek,rt5665"},
+       {.compatible = "realtek,rt5666"},
+       {.compatible = "realtek,rt5668"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, rt5665_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt5665_acpi_match[] = {
+       {"10EC5665", 0,},
+       {"10EC5666", 0,},
+       {"10EC5668", 0,},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match);
+#endif
+
+struct i2c_driver rt5665_i2c_driver = {
+       .driver = {
+               .name = "rt5665",
+               .of_match_table = of_match_ptr(rt5665_of_match),
+               .acpi_match_table = ACPI_PTR(rt5665_acpi_match),
+       },
+       .probe = rt5665_i2c_probe,
+       .remove = rt5665_i2c_remove,
+       .shutdown = rt5665_i2c_shutdown,
+       .id_table = rt5665_i2c_id,
+};
+module_i2c_driver(rt5665_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5665 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h
new file mode 100644 (file)
index 0000000..12f7080
--- /dev/null
@@ -0,0 +1,1990 @@
+/*
+ * rt5665.h  --  RT5665/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2016 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5665_H__
+#define __RT5665_H__
+
+#include <sound/rt5665.h>
+
+#define DEVICE_ID 0x6451
+
+/* Info */
+#define RT5665_RESET                           0x0000
+#define RT5665_VENDOR_ID                       0x00fd
+#define RT5665_VENDOR_ID_1                     0x00fe
+#define RT5665_DEVICE_ID                       0x00ff
+/*  I/O - Output */
+#define RT5665_LOUT                            0x0001
+#define RT5665_HP_CTRL_1                       0x0002
+#define RT5665_HP_CTRL_2                       0x0003
+#define RT5665_MONO_OUT                                0x0004
+#define RT5665_HPL_GAIN                                0x0005
+#define RT5665_HPR_GAIN                                0x0006
+#define RT5665_MONO_GAIN                       0x0007
+
+/* I/O - Input */
+#define RT5665_CAL_BST_CTRL                    0x000a
+#define RT5665_CBJ_BST_CTRL                    0x000b
+#define RT5665_IN1_IN2                         0x000c
+#define RT5665_IN3_IN4                         0x000d
+#define RT5665_INL1_INR1_VOL                   0x000f
+/* I/O - Speaker */
+#define RT5665_EJD_CTRL_1                      0x0010
+#define RT5665_EJD_CTRL_2                      0x0011
+#define RT5665_EJD_CTRL_3                      0x0012
+#define RT5665_EJD_CTRL_4                      0x0013
+#define RT5665_EJD_CTRL_5                      0x0014
+#define RT5665_EJD_CTRL_6                      0x0015
+#define RT5665_EJD_CTRL_7                      0x0016
+/* I/O - ADC/DAC/DMIC */
+#define RT5665_DAC2_CTRL                       0x0017
+#define RT5665_DAC2_DIG_VOL                    0x0018
+#define RT5665_DAC1_DIG_VOL                    0x0019
+#define RT5665_DAC3_DIG_VOL                    0x001a
+#define RT5665_DAC3_CTRL                       0x001b
+#define RT5665_STO1_ADC_DIG_VOL                        0x001c
+#define RT5665_MONO_ADC_DIG_VOL                        0x001d
+#define RT5665_STO2_ADC_DIG_VOL                        0x001e
+#define RT5665_STO1_ADC_BOOST                  0x001f
+#define RT5665_MONO_ADC_BOOST                  0x0020
+#define RT5665_STO2_ADC_BOOST                  0x0021
+#define RT5665_HP_IMP_GAIN_1                   0x0022
+#define RT5665_HP_IMP_GAIN_2                   0x0023
+/* Mixer - D-D */
+#define RT5665_STO1_ADC_MIXER                  0x0026
+#define RT5665_MONO_ADC_MIXER                  0x0027
+#define RT5665_STO2_ADC_MIXER                  0x0028
+#define RT5665_AD_DA_MIXER                     0x0029
+#define RT5665_STO1_DAC_MIXER                  0x002a
+#define RT5665_MONO_DAC_MIXER                  0x002b
+#define RT5665_STO2_DAC_MIXER                  0x002c
+#define RT5665_A_DAC1_MUX                      0x002d
+#define RT5665_A_DAC2_MUX                      0x002e
+#define RT5665_DIG_INF2_DATA                   0x002f
+#define RT5665_DIG_INF3_DATA                   0x0030
+/* Mixer - PDM */
+#define RT5665_PDM_OUT_CTRL                    0x0031
+#define RT5665_PDM_DATA_CTRL_1                 0x0032
+#define RT5665_PDM_DATA_CTRL_2                 0x0033
+#define RT5665_PDM_DATA_CTRL_3                 0x0034
+#define RT5665_PDM_DATA_CTRL_4                 0x0035
+/* Mixer - ADC */
+#define RT5665_REC1_GAIN                       0x003a
+#define RT5665_REC1_L1_MIXER                   0x003b
+#define RT5665_REC1_L2_MIXER                   0x003c
+#define RT5665_REC1_R1_MIXER                   0x003d
+#define RT5665_REC1_R2_MIXER                   0x003e
+#define RT5665_REC2_GAIN                       0x003f
+#define RT5665_REC2_L1_MIXER                   0x0040
+#define RT5665_REC2_L2_MIXER                   0x0041
+#define RT5665_REC2_R1_MIXER                   0x0042
+#define RT5665_REC2_R2_MIXER                   0x0043
+#define RT5665_CAL_REC                         0x0044
+/* Mixer - DAC */
+#define RT5665_ALC_BACK_GAIN                   0x0049
+#define RT5665_MONOMIX_GAIN                    0x004a
+#define RT5665_MONOMIX_IN_GAIN                 0x004b
+#define RT5665_OUT_L_GAIN                      0x004d
+#define RT5665_OUT_L_MIXER                     0x004e
+#define RT5665_OUT_R_GAIN                      0x004f
+#define RT5665_OUT_R_MIXER                     0x0050
+#define RT5665_LOUT_MIXER                      0x0052
+/* Power */
+#define RT5665_PWR_DIG_1                       0x0061
+#define RT5665_PWR_DIG_2                       0x0062
+#define RT5665_PWR_ANLG_1                      0x0063
+#define RT5665_PWR_ANLG_2                      0x0064
+#define RT5665_PWR_ANLG_3                      0x0065
+#define RT5665_PWR_MIXER                       0x0066
+#define RT5665_PWR_VOL                         0x0067
+/* Clock Detect */
+#define RT5665_CLK_DET                         0x006b
+/* Filter */
+#define RT5665_HPF_CTRL1                       0x006d
+/* DMIC */
+#define RT5665_DMIC_CTRL_1                     0x006e
+#define RT5665_DMIC_CTRL_2                     0x006f
+/* Format - ADC/DAC */
+#define RT5665_I2S1_SDP                                0x0070
+#define RT5665_I2S2_SDP                                0x0071
+#define RT5665_I2S3_SDP                                0x0072
+#define RT5665_ADDA_CLK_1                      0x0073
+#define RT5665_ADDA_CLK_2                      0x0074
+#define RT5665_I2S1_F_DIV_CTRL_1               0x0075
+#define RT5665_I2S1_F_DIV_CTRL_2               0x0076
+/* Format - TDM Control */
+#define RT5665_TDM_CTRL_1                      0x0078
+#define RT5665_TDM_CTRL_2                      0x0079
+#define RT5665_TDM_CTRL_3                      0x007a
+#define RT5665_TDM_CTRL_4                      0x007b
+#define RT5665_TDM_CTRL_5                      0x007c
+#define RT5665_TDM_CTRL_6                      0x007d
+#define RT5665_TDM_CTRL_7                      0x007e
+#define RT5665_TDM_CTRL_8                      0x007f
+/* Function - Analog */
+#define RT5665_GLB_CLK                         0x0080
+#define RT5665_PLL_CTRL_1                      0x0081
+#define RT5665_PLL_CTRL_2                      0x0082
+#define RT5665_ASRC_1                          0x0083
+#define RT5665_ASRC_2                          0x0084
+#define RT5665_ASRC_3                          0x0085
+#define RT5665_ASRC_4                          0x0086
+#define RT5665_ASRC_5                          0x0087
+#define RT5665_ASRC_6                          0x0088
+#define RT5665_ASRC_7                          0x0089
+#define RT5665_ASRC_8                          0x008a
+#define RT5665_ASRC_9                          0x008b
+#define RT5665_ASRC_10                         0x008c
+#define RT5665_DEPOP_1                         0x008e
+#define RT5665_DEPOP_2                         0x008f
+#define RT5665_HP_CHARGE_PUMP_1                        0x0091
+#define RT5665_HP_CHARGE_PUMP_2                        0x0092
+#define RT5665_MICBIAS_1                       0x0093
+#define RT5665_MICBIAS_2                       0x0094
+#define RT5665_ASRC_12                         0x0098
+#define RT5665_ASRC_13                         0x0099
+#define RT5665_ASRC_14                         0x009a
+#define RT5665_RC_CLK_CTRL                     0x009f
+#define RT5665_I2S_M_CLK_CTRL_1                        0x00a0
+#define RT5665_I2S2_F_DIV_CTRL_1               0x00a1
+#define RT5665_I2S2_F_DIV_CTRL_2               0x00a2
+#define RT5665_I2S3_F_DIV_CTRL_1               0x00a3
+#define RT5665_I2S3_F_DIV_CTRL_2               0x00a4
+/* Function - Digital */
+#define RT5665_EQ_CTRL_1                       0x00ae
+#define RT5665_EQ_CTRL_2                       0x00af
+#define RT5665_IRQ_CTRL_1                      0x00b6
+#define RT5665_IRQ_CTRL_2                      0x00b7
+#define RT5665_IRQ_CTRL_3                      0x00b8
+#define RT5665_IRQ_CTRL_4                      0x00b9
+#define RT5665_IRQ_CTRL_5                      0x00ba
+#define RT5665_IRQ_CTRL_6                      0x00bb
+#define RT5665_INT_ST_1                                0x00be
+#define RT5665_GPIO_CTRL_1                     0x00c0
+#define RT5665_GPIO_CTRL_2                     0x00c1
+#define RT5665_GPIO_CTRL_3                     0x00c2
+#define RT5665_GPIO_CTRL_4                     0x00c3
+#define RT5665_GPIO_STA                                0x00c4
+#define RT5665_HP_AMP_DET_CTRL_1               0x00d0
+#define RT5665_HP_AMP_DET_CTRL_2               0x00d1
+#define RT5665_MID_HP_AMP_DET                  0x00d3
+#define RT5665_LOW_HP_AMP_DET                  0x00d4
+#define RT5665_SV_ZCD_1                                0x00d9
+#define RT5665_SV_ZCD_2                                0x00da
+#define RT5665_IL_CMD_1                                0x00db
+#define RT5665_IL_CMD_2                                0x00dc
+#define RT5665_IL_CMD_3                                0x00dd
+#define RT5665_IL_CMD_4                                0x00de
+#define RT5665_4BTN_IL_CMD_1                   0x00df
+#define RT5665_4BTN_IL_CMD_2                   0x00e0
+#define RT5665_4BTN_IL_CMD_3                   0x00e1
+#define RT5665_PSV_IL_CMD_1                    0x00e2
+
+#define RT5665_ADC_STO1_HP_CTRL_1              0x00ea
+#define RT5665_ADC_STO1_HP_CTRL_2              0x00eb
+#define RT5665_ADC_MONO_HP_CTRL_1              0x00ec
+#define RT5665_ADC_MONO_HP_CTRL_2              0x00ed
+#define RT5665_ADC_STO2_HP_CTRL_1              0x00ee
+#define RT5665_ADC_STO2_HP_CTRL_2              0x00ef
+#define RT5665_AJD1_CTRL                       0x00f0
+#define RT5665_JD1_THD                         0x00f1
+#define RT5665_JD2_THD                         0x00f2
+#define RT5665_JD_CTRL_1                       0x00f6
+#define RT5665_JD_CTRL_2                       0x00f7
+#define RT5665_JD_CTRL_3                       0x00f8
+/* General Control */
+#define RT5665_DIG_MISC                                0x00fa
+#define RT5665_DUMMY_2                         0x00fb
+#define RT5665_DUMMY_3                         0x00fc
+
+#define RT5665_DAC_ADC_DIG_VOL1                        0x0100
+#define RT5665_DAC_ADC_DIG_VOL2                        0x0101
+#define RT5665_BIAS_CUR_CTRL_1                 0x010a
+#define RT5665_BIAS_CUR_CTRL_2                 0x010b
+#define RT5665_BIAS_CUR_CTRL_3                 0x010c
+#define RT5665_BIAS_CUR_CTRL_4                 0x010d
+#define RT5665_BIAS_CUR_CTRL_5                 0x010e
+#define RT5665_BIAS_CUR_CTRL_6                 0x010f
+#define RT5665_BIAS_CUR_CTRL_7                 0x0110
+#define RT5665_BIAS_CUR_CTRL_8                 0x0111
+#define RT5665_BIAS_CUR_CTRL_9                 0x0112
+#define RT5665_BIAS_CUR_CTRL_10                        0x0113
+#define RT5665_VREF_REC_OP_FB_CAP_CTRL         0x0117
+#define RT5665_CHARGE_PUMP_1                   0x0125
+#define RT5665_DIG_IN_CTRL_1                   0x0132
+#define RT5665_DIG_IN_CTRL_2                   0x0133
+#define RT5665_PAD_DRIVING_CTRL                        0x0137
+#define RT5665_SOFT_RAMP_DEPOP                 0x0138
+#define RT5665_PLL                             0x0139
+#define RT5665_CHOP_DAC                                0x013a
+#define RT5665_CHOP_ADC                                0x013b
+#define RT5665_CALIB_ADC_CTRL                  0x013c
+#define RT5665_VOL_TEST                                0x013f
+#define RT5665_TEST_MODE_CTRL_1                        0x0145
+#define RT5665_TEST_MODE_CTRL_2                        0x0146
+#define RT5665_TEST_MODE_CTRL_3                        0x0147
+#define RT5665_TEST_MODE_CTRL_4                        0x0148
+#define RT5665_BASSBACK_CTRL                   0x0150
+#define RT5665_STO_NG2_CTRL_1                  0x0160
+#define RT5665_STO_NG2_CTRL_2                  0x0161
+#define RT5665_STO_NG2_CTRL_3                  0x0162
+#define RT5665_STO_NG2_CTRL_4                  0x0163
+#define RT5665_STO_NG2_CTRL_5                  0x0164
+#define RT5665_STO_NG2_CTRL_6                  0x0165
+#define RT5665_STO_NG2_CTRL_7                  0x0166
+#define RT5665_STO_NG2_CTRL_8                  0x0167
+#define RT5665_MONO_NG2_CTRL_1                 0x0170
+#define RT5665_MONO_NG2_CTRL_2                 0x0171
+#define RT5665_MONO_NG2_CTRL_3                 0x0172
+#define RT5665_MONO_NG2_CTRL_4                 0x0173
+#define RT5665_MONO_NG2_CTRL_5                 0x0174
+#define RT5665_MONO_NG2_CTRL_6                 0x0175
+#define RT5665_STO1_DAC_SIL_DET                        0x0190
+#define RT5665_MONOL_DAC_SIL_DET               0x0191
+#define RT5665_MONOR_DAC_SIL_DET               0x0192
+#define RT5665_STO2_DAC_SIL_DET                        0x0193
+#define RT5665_SIL_PSV_CTRL1                   0x0194
+#define RT5665_SIL_PSV_CTRL2                   0x0195
+#define RT5665_SIL_PSV_CTRL3                   0x0196
+#define RT5665_SIL_PSV_CTRL4                   0x0197
+#define RT5665_SIL_PSV_CTRL5                   0x0198
+#define RT5665_SIL_PSV_CTRL6                   0x0199
+#define RT5665_MONO_AMP_CALIB_CTRL_1           0x01a0
+#define RT5665_MONO_AMP_CALIB_CTRL_2           0x01a1
+#define RT5665_MONO_AMP_CALIB_CTRL_3           0x01a2
+#define RT5665_MONO_AMP_CALIB_CTRL_4           0x01a3
+#define RT5665_MONO_AMP_CALIB_CTRL_5           0x01a4
+#define RT5665_MONO_AMP_CALIB_CTRL_6           0x01a5
+#define RT5665_MONO_AMP_CALIB_CTRL_7           0x01a6
+#define RT5665_MONO_AMP_CALIB_STA1             0x01a7
+#define RT5665_MONO_AMP_CALIB_STA2             0x01a8
+#define RT5665_MONO_AMP_CALIB_STA3             0x01a9
+#define RT5665_MONO_AMP_CALIB_STA4             0x01aa
+#define RT5665_MONO_AMP_CALIB_STA6             0x01ab
+#define RT5665_HP_IMP_SENS_CTRL_01             0x01b5
+#define RT5665_HP_IMP_SENS_CTRL_02             0x01b6
+#define RT5665_HP_IMP_SENS_CTRL_03             0x01b7
+#define RT5665_HP_IMP_SENS_CTRL_04             0x01b8
+#define RT5665_HP_IMP_SENS_CTRL_05             0x01b9
+#define RT5665_HP_IMP_SENS_CTRL_06             0x01ba
+#define RT5665_HP_IMP_SENS_CTRL_07             0x01bb
+#define RT5665_HP_IMP_SENS_CTRL_08             0x01bc
+#define RT5665_HP_IMP_SENS_CTRL_09             0x01bd
+#define RT5665_HP_IMP_SENS_CTRL_10             0x01be
+#define RT5665_HP_IMP_SENS_CTRL_11             0x01bf
+#define RT5665_HP_IMP_SENS_CTRL_12             0x01c0
+#define RT5665_HP_IMP_SENS_CTRL_13             0x01c1
+#define RT5665_HP_IMP_SENS_CTRL_14             0x01c2
+#define RT5665_HP_IMP_SENS_CTRL_15             0x01c3
+#define RT5665_HP_IMP_SENS_CTRL_16             0x01c4
+#define RT5665_HP_IMP_SENS_CTRL_17             0x01c5
+#define RT5665_HP_IMP_SENS_CTRL_18             0x01c6
+#define RT5665_HP_IMP_SENS_CTRL_19             0x01c7
+#define RT5665_HP_IMP_SENS_CTRL_20             0x01c8
+#define RT5665_HP_IMP_SENS_CTRL_21             0x01c9
+#define RT5665_HP_IMP_SENS_CTRL_22             0x01ca
+#define RT5665_HP_IMP_SENS_CTRL_23             0x01cb
+#define RT5665_HP_IMP_SENS_CTRL_24             0x01cc
+#define RT5665_HP_IMP_SENS_CTRL_25             0x01cd
+#define RT5665_HP_IMP_SENS_CTRL_26             0x01ce
+#define RT5665_HP_IMP_SENS_CTRL_27             0x01cf
+#define RT5665_HP_IMP_SENS_CTRL_28             0x01d0
+#define RT5665_HP_IMP_SENS_CTRL_29             0x01d1
+#define RT5665_HP_IMP_SENS_CTRL_30             0x01d2
+#define RT5665_HP_IMP_SENS_CTRL_31             0x01d3
+#define RT5665_HP_IMP_SENS_CTRL_32             0x01d4
+#define RT5665_HP_IMP_SENS_CTRL_33             0x01d5
+#define RT5665_HP_IMP_SENS_CTRL_34             0x01d6
+#define RT5665_HP_LOGIC_CTRL_1                 0x01da
+#define RT5665_HP_LOGIC_CTRL_2                 0x01db
+#define RT5665_HP_LOGIC_CTRL_3                 0x01dc
+#define RT5665_HP_CALIB_CTRL_1                 0x01de
+#define RT5665_HP_CALIB_CTRL_2                 0x01df
+#define RT5665_HP_CALIB_CTRL_3                 0x01e0
+#define RT5665_HP_CALIB_CTRL_4                 0x01e1
+#define RT5665_HP_CALIB_CTRL_5                 0x01e2
+#define RT5665_HP_CALIB_CTRL_6                 0x01e3
+#define RT5665_HP_CALIB_CTRL_7                 0x01e4
+#define RT5665_HP_CALIB_CTRL_9                 0x01e6
+#define RT5665_HP_CALIB_CTRL_10                        0x01e7
+#define RT5665_HP_CALIB_CTRL_11                        0x01e8
+#define RT5665_HP_CALIB_STA_1                  0x01ea
+#define RT5665_HP_CALIB_STA_2                  0x01eb
+#define RT5665_HP_CALIB_STA_3                  0x01ec
+#define RT5665_HP_CALIB_STA_4                  0x01ed
+#define RT5665_HP_CALIB_STA_5                  0x01ee
+#define RT5665_HP_CALIB_STA_6                  0x01ef
+#define RT5665_HP_CALIB_STA_7                  0x01f0
+#define RT5665_HP_CALIB_STA_8                  0x01f1
+#define RT5665_HP_CALIB_STA_9                  0x01f2
+#define RT5665_HP_CALIB_STA_10                 0x01f3
+#define RT5665_HP_CALIB_STA_11                 0x01f4
+#define RT5665_PGM_TAB_CTRL1                   0x0200
+#define RT5665_PGM_TAB_CTRL2                   0x0201
+#define RT5665_PGM_TAB_CTRL3                   0x0202
+#define RT5665_PGM_TAB_CTRL4                   0x0203
+#define RT5665_PGM_TAB_CTRL5                   0x0204
+#define RT5665_PGM_TAB_CTRL6                   0x0205
+#define RT5665_PGM_TAB_CTRL7                   0x0206
+#define RT5665_PGM_TAB_CTRL8                   0x0207
+#define RT5665_PGM_TAB_CTRL9                   0x0208
+#define RT5665_SAR_IL_CMD_1                    0x0210
+#define RT5665_SAR_IL_CMD_2                    0x0211
+#define RT5665_SAR_IL_CMD_3                    0x0212
+#define RT5665_SAR_IL_CMD_4                    0x0213
+#define RT5665_SAR_IL_CMD_5                    0x0214
+#define RT5665_SAR_IL_CMD_6                    0x0215
+#define RT5665_SAR_IL_CMD_7                    0x0216
+#define RT5665_SAR_IL_CMD_8                    0x0217
+#define RT5665_SAR_IL_CMD_9                    0x0218
+#define RT5665_SAR_IL_CMD_10                   0x0219
+#define RT5665_SAR_IL_CMD_11                   0x021a
+#define RT5665_SAR_IL_CMD_12                   0x021b
+#define RT5665_DRC1_CTRL_0                     0x02ff
+#define RT5665_DRC1_CTRL_1                     0x0300
+#define RT5665_DRC1_CTRL_2                     0x0301
+#define RT5665_DRC1_CTRL_3                     0x0302
+#define RT5665_DRC1_CTRL_4                     0x0303
+#define RT5665_DRC1_CTRL_5                     0x0304
+#define RT5665_DRC1_CTRL_6                     0x0305
+#define RT5665_DRC1_HARD_LMT_CTRL_1            0x0306
+#define RT5665_DRC1_HARD_LMT_CTRL_2            0x0307
+#define RT5665_DRC1_PRIV_1                     0x0310
+#define RT5665_DRC1_PRIV_2                     0x0311
+#define RT5665_DRC1_PRIV_3                     0x0312
+#define RT5665_DRC1_PRIV_4                     0x0313
+#define RT5665_DRC1_PRIV_5                     0x0314
+#define RT5665_DRC1_PRIV_6                     0x0315
+#define RT5665_DRC1_PRIV_7                     0x0316
+#define RT5665_DRC1_PRIV_8                     0x0317
+#define RT5665_ALC_PGA_CTRL_1                  0x0330
+#define RT5665_ALC_PGA_CTRL_2                  0x0331
+#define RT5665_ALC_PGA_CTRL_3                  0x0332
+#define RT5665_ALC_PGA_CTRL_4                  0x0333
+#define RT5665_ALC_PGA_CTRL_5                  0x0334
+#define RT5665_ALC_PGA_CTRL_6                  0x0335
+#define RT5665_ALC_PGA_CTRL_7                  0x0336
+#define RT5665_ALC_PGA_CTRL_8                  0x0337
+#define RT5665_ALC_PGA_STA_1                   0x0338
+#define RT5665_ALC_PGA_STA_2                   0x0339
+#define RT5665_ALC_PGA_STA_3                   0x033a
+#define RT5665_EQ_AUTO_RCV_CTRL1               0x03c0
+#define RT5665_EQ_AUTO_RCV_CTRL2               0x03c1
+#define RT5665_EQ_AUTO_RCV_CTRL3               0x03c2
+#define RT5665_EQ_AUTO_RCV_CTRL4               0x03c3
+#define RT5665_EQ_AUTO_RCV_CTRL5               0x03c4
+#define RT5665_EQ_AUTO_RCV_CTRL6               0x03c5
+#define RT5665_EQ_AUTO_RCV_CTRL7               0x03c6
+#define RT5665_EQ_AUTO_RCV_CTRL8               0x03c7
+#define RT5665_EQ_AUTO_RCV_CTRL9               0x03c8
+#define RT5665_EQ_AUTO_RCV_CTRL10              0x03c9
+#define RT5665_EQ_AUTO_RCV_CTRL11              0x03ca
+#define RT5665_EQ_AUTO_RCV_CTRL12              0x03cb
+#define RT5665_EQ_AUTO_RCV_CTRL13              0x03cc
+#define RT5665_ADC_L_EQ_LPF1_A1                        0x03d0
+#define RT5665_R_EQ_LPF1_A1                    0x03d1
+#define RT5665_L_EQ_LPF1_H0                    0x03d2
+#define RT5665_R_EQ_LPF1_H0                    0x03d3
+#define RT5665_L_EQ_BPF1_A1                    0x03d4
+#define RT5665_R_EQ_BPF1_A1                    0x03d5
+#define RT5665_L_EQ_BPF1_A2                    0x03d6
+#define RT5665_R_EQ_BPF1_A2                    0x03d7
+#define RT5665_L_EQ_BPF1_H0                    0x03d8
+#define RT5665_R_EQ_BPF1_H0                    0x03d9
+#define RT5665_L_EQ_BPF2_A1                    0x03da
+#define RT5665_R_EQ_BPF2_A1                    0x03db
+#define RT5665_L_EQ_BPF2_A2                    0x03dc
+#define RT5665_R_EQ_BPF2_A2                    0x03dd
+#define RT5665_L_EQ_BPF2_H0                    0x03de
+#define RT5665_R_EQ_BPF2_H0                    0x03df
+#define RT5665_L_EQ_BPF3_A1                    0x03e0
+#define RT5665_R_EQ_BPF3_A1                    0x03e1
+#define RT5665_L_EQ_BPF3_A2                    0x03e2
+#define RT5665_R_EQ_BPF3_A2                    0x03e3
+#define RT5665_L_EQ_BPF3_H0                    0x03e4
+#define RT5665_R_EQ_BPF3_H0                    0x03e5
+#define RT5665_L_EQ_BPF4_A1                    0x03e6
+#define RT5665_R_EQ_BPF4_A1                    0x03e7
+#define RT5665_L_EQ_BPF4_A2                    0x03e8
+#define RT5665_R_EQ_BPF4_A2                    0x03e9
+#define RT5665_L_EQ_BPF4_H0                    0x03ea
+#define RT5665_R_EQ_BPF4_H0                    0x03eb
+#define RT5665_L_EQ_HPF1_A1                    0x03ec
+#define RT5665_R_EQ_HPF1_A1                    0x03ed
+#define RT5665_L_EQ_HPF1_H0                    0x03ee
+#define RT5665_R_EQ_HPF1_H0                    0x03ef
+#define RT5665_L_EQ_PRE_VOL                    0x03f0
+#define RT5665_R_EQ_PRE_VOL                    0x03f1
+#define RT5665_L_EQ_POST_VOL                   0x03f2
+#define RT5665_R_EQ_POST_VOL                   0x03f3
+#define RT5665_SCAN_MODE_CTRL                  0x07f0
+#define RT5665_I2C_MODE                                0x07fa
+
+
+
+/* global definition */
+#define RT5665_L_MUTE                          (0x1 << 15)
+#define RT5665_L_MUTE_SFT                      15
+#define RT5665_VOL_L_MUTE                      (0x1 << 14)
+#define RT5665_VOL_L_SFT                       14
+#define RT5665_R_MUTE                          (0x1 << 7)
+#define RT5665_R_MUTE_SFT                      7
+#define RT5665_VOL_R_MUTE                      (0x1 << 6)
+#define RT5665_VOL_R_SFT                       6
+#define RT5665_L_VOL_MASK                      (0x3f << 8)
+#define RT5665_L_VOL_SFT                       8
+#define RT5665_R_VOL_MASK                      (0x3f)
+#define RT5665_R_VOL_SFT                       0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5665_G_HP                            (0xf << 8)
+#define RT5665_G_HP_SFT                                8
+#define RT5665_G_STO_DA_DMIX                   (0xf)
+#define RT5665_G_STO_DA_SFT                    0
+
+/* CBJ Control (0x000b) */
+#define RT5665_BST_CBJ_MASK                    (0xf << 8)
+#define RT5665_BST_CBJ_SFT                     8
+
+/* IN1/IN2 Control (0x000c) */
+#define RT5665_IN1_DF_MASK                     (0x1 << 15)
+#define RT5665_IN1_DF                          15
+#define RT5665_BST1_MASK                       (0x7f << 8)
+#define RT5665_BST1_SFT                                8
+#define RT5665_IN2_DF_MASK                     (0x1 << 7)
+#define RT5665_IN2_DF                          7
+#define RT5665_BST2_MASK                       (0x7f)
+#define RT5665_BST2_SFT                                0
+
+/* IN3/IN4 Control (0x000d) */
+#define RT5665_IN3_DF_MASK                     (0x1 << 15)
+#define RT5665_IN3_DF                          15
+#define RT5665_BST3_MASK                       (0x7f << 8)
+#define RT5665_BST3_SFT                                8
+#define RT5665_IN4_DF_MASK                     (0x1 << 7)
+#define RT5665_IN4_DF                          7
+#define RT5665_BST4_MASK                       (0x7f)
+#define RT5665_BST4_SFT                                0
+
+/* INL and INR Volume Control (0x000f) */
+#define RT5665_INL_VOL_MASK                    (0x1f << 8)
+#define RT5665_INL_VOL_SFT                     8
+#define RT5665_INR_VOL_MASK                    (0x1f)
+#define RT5665_INR_VOL_SFT                     0
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5665_EMB_JD_EN                       (0x1 << 15)
+#define RT5665_EMB_JD_EN_SFT                   15
+#define RT5665_JD_MODE                         (0x1 << 13)
+#define RT5665_JD_MODE_SFT                     13
+#define RT5665_POLA_EXT_JD_MASK                        (0x1 << 11)
+#define RT5665_POLA_EXT_JD_LOW                 (0x1 << 11)
+#define RT5665_POLA_EXT_JD_HIGH                        (0x0 << 11)
+#define RT5665_EXT_JD_DIG                      (0x1 << 9)
+#define RT5665_POL_FAST_OFF_MASK               (0x1 << 8)
+#define RT5665_POL_FAST_OFF_HIGH               (0x1 << 8)
+#define RT5665_POL_FAST_OFF_LOW                        (0x0 << 8)
+#define RT5665_VREF_POW_MASK                   (0x1 << 6)
+#define RT5665_VREF_POW_FSM                    (0x0 << 6)
+#define RT5665_VREF_POW_REG                    (0x1 << 6)
+#define RT5665_MB1_PATH_MASK                   (0x1 << 5)
+#define RT5665_CTRL_MB1_REG                    (0x1 << 5)
+#define RT5665_CTRL_MB1_FSM                    (0x0 << 5)
+#define RT5665_MB2_PATH_MASK                   (0x1 << 4)
+#define RT5665_CTRL_MB2_REG                    (0x1 << 4)
+#define RT5665_CTRL_MB2_FSM                    (0x0 << 4)
+#define RT5665_TRIG_JD_MASK                    (0x1 << 3)
+#define RT5665_TRIG_JD_HIGH                    (0x1 << 3)
+#define RT5665_TRIG_JD_LOW                     (0x0 << 3)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5665_EXT_JD_SRC                      (0x7 << 4)
+#define RT5665_EXT_JD_SRC_SFT                  4
+#define RT5665_EXT_JD_SRC_GPIO_JD1             (0x0 << 4)
+#define RT5665_EXT_JD_SRC_GPIO_JD2             (0x1 << 4)
+#define RT5665_EXT_JD_SRC_JD1_1                        (0x2 << 4)
+#define RT5665_EXT_JD_SRC_JD1_2                        (0x3 << 4)
+#define RT5665_EXT_JD_SRC_JD2                  (0x4 << 4)
+#define RT5665_EXT_JD_SRC_JD3                  (0x5 << 4)
+#define RT5665_EXT_JD_SRC_MANUAL               (0x6 << 4)
+
+/* Combo Jack and Type Detection Control 4 (0x0013) */
+#define RT5665_SEL_SHT_MID_TON_MASK            (0x3 << 12)
+#define RT5665_SEL_SHT_MID_TON_2               (0x0 << 12)
+#define RT5665_SEL_SHT_MID_TON_3               (0x1 << 12)
+#define RT5665_CBJ_JD_TEST_MASK                        (0x1 << 6)
+#define RT5665_CBJ_JD_TEST_NORM                        (0x0 << 6)
+#define RT5665_CBJ_JD_TEST_MODE                        (0x1 << 6)
+
+/* Slience Detection Control (0x0015) */
+#define RT5665_SIL_DET_MASK                    (0x1 << 15)
+#define RT5665_SIL_DET_DIS                     (0x0 << 15)
+#define RT5665_SIL_DET_EN                      (0x1 << 15)
+
+/* DAC2 Control (0x0017) */
+#define RT5665_M_DAC2_L_VOL                    (0x1 << 13)
+#define RT5665_M_DAC2_L_VOL_SFT                        13
+#define RT5665_M_DAC2_R_VOL                    (0x1 << 12)
+#define RT5665_M_DAC2_R_VOL_SFT                        12
+#define RT5665_DAC_L2_SEL_MASK                 (0x7 << 4)
+#define RT5665_DAC_L2_SEL_SFT                  4
+#define RT5665_DAC_R2_SEL_MASK                 (0x7 << 0)
+#define RT5665_DAC_R2_SEL_SFT                  0
+
+/* Sidetone Control (0x0018) */
+#define RT5665_ST_SEL_MASK                     (0x7 << 9)
+#define RT5665_ST_SEL_SFT                      9
+#define RT5665_ST_EN                           (0x1 << 6)
+#define RT5665_ST_EN_SFT                       6
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5665_DAC_L1_VOL_MASK                 (0xff << 8)
+#define RT5665_DAC_L1_VOL_SFT                  8
+#define RT5665_DAC_R1_VOL_MASK                 (0xff)
+#define RT5665_DAC_R1_VOL_SFT                  0
+
+/* DAC2 Digital Volume (0x001a) */
+#define RT5665_DAC_L2_VOL_MASK                 (0xff << 8)
+#define RT5665_DAC_L2_VOL_SFT                  8
+#define RT5665_DAC_R2_VOL_MASK                 (0xff)
+#define RT5665_DAC_R2_VOL_SFT                  0
+
+/* DAC3 Control (0x001b) */
+#define RT5665_M_DAC3_L_VOL                    (0x1 << 13)
+#define RT5665_M_DAC3_L_VOL_SFT                        13
+#define RT5665_M_DAC3_R_VOL                    (0x1 << 12)
+#define RT5665_M_DAC3_R_VOL_SFT                        12
+#define RT5665_DAC_L3_SEL_MASK                 (0x7 << 4)
+#define RT5665_DAC_L3_SEL_SFT                  4
+#define RT5665_DAC_R3_SEL_MASK                 (0x7 << 0)
+#define RT5665_DAC_R3_SEL_SFT                  0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5665_ADC_L_VOL_MASK                  (0x7f << 8)
+#define RT5665_ADC_L_VOL_SFT                   8
+#define RT5665_ADC_R_VOL_MASK                  (0x7f)
+#define RT5665_ADC_R_VOL_SFT                   0
+
+/* Mono ADC Digital Volume Control (0x001d) */
+#define RT5665_MONO_ADC_L_VOL_MASK             (0x7f << 8)
+#define RT5665_MONO_ADC_L_VOL_SFT              8
+#define RT5665_MONO_ADC_R_VOL_MASK             (0x7f)
+#define RT5665_MONO_ADC_R_VOL_SFT              0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5665_STO1_ADC_L_BST_MASK             (0x3 << 14)
+#define RT5665_STO1_ADC_L_BST_SFT              14
+#define RT5665_STO1_ADC_R_BST_MASK             (0x3 << 12)
+#define RT5665_STO1_ADC_R_BST_SFT              12
+
+/* Mono ADC Boost Gain Control (0x0020) */
+#define RT5665_MONO_ADC_L_BST_MASK             (0x3 << 14)
+#define RT5665_MONO_ADC_L_BST_SFT              14
+#define RT5665_MONO_ADC_R_BST_MASK             (0x3 << 12)
+#define RT5665_MONO_ADC_R_BST_SFT              12
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5665_STO2_ADC_L_BST_MASK             (0x3 << 14)
+#define RT5665_STO2_ADC_L_BST_SFT              14
+#define RT5665_STO2_ADC_R_BST_MASK             (0x3 << 12)
+#define RT5665_STO2_ADC_R_BST_SFT              12
+
+/* Stereo1 ADC Mixer Control (0x0026) */
+#define RT5665_M_STO1_ADC_L1                   (0x1 << 15)
+#define RT5665_M_STO1_ADC_L1_SFT               15
+#define RT5665_M_STO1_ADC_L2                   (0x1 << 14)
+#define RT5665_M_STO1_ADC_L2_SFT               14
+#define RT5665_STO1_ADC1L_SRC_MASK             (0x1 << 13)
+#define RT5665_STO1_ADC1L_SRC_SFT              13
+#define RT5665_STO1_ADC1_SRC_ADC               (0x1 << 13)
+#define RT5665_STO1_ADC1_SRC_DACMIX            (0x0 << 13)
+#define RT5665_STO1_ADC2L_SRC_MASK             (0x1 << 12)
+#define RT5665_STO1_ADC2L_SRC_SFT              12
+#define RT5665_STO1_ADCL_SRC_MASK              (0x3 << 10)
+#define RT5665_STO1_ADCL_SRC_SFT               10
+#define RT5665_STO1_DD_L_SRC_MASK              (0x1 << 9)
+#define RT5665_STO1_DD_L_SRC_SFT               9
+#define RT5665_STO1_DMIC_SRC_MASK              (0x1 << 8)
+#define RT5665_STO1_DMIC_SRC_SFT               8
+#define RT5665_STO1_DMIC_SRC_DMIC2             (0x1 << 8)
+#define RT5665_STO1_DMIC_SRC_DMIC1             (0x0 << 8)
+#define RT5665_M_STO1_ADC_R1                   (0x1 << 7)
+#define RT5665_M_STO1_ADC_R1_SFT               7
+#define RT5665_M_STO1_ADC_R2                   (0x1 << 6)
+#define RT5665_M_STO1_ADC_R2_SFT               6
+#define RT5665_STO1_ADC1R_SRC_MASK             (0x1 << 5)
+#define RT5665_STO1_ADC1R_SRC_SFT              5
+#define RT5665_STO1_ADC2R_SRC_MASK             (0x1 << 4)
+#define RT5665_STO1_ADC2R_SRC_SFT              4
+#define RT5665_STO1_ADCR_SRC_MASK              (0x3 << 2)
+#define RT5665_STO1_ADCR_SRC_SFT               2
+#define RT5665_STO1_DD_R_SRC_MASK              (0x3)
+#define RT5665_STO1_DD_R_SRC_SFT               0
+
+
+/* Mono1 ADC Mixer control (0x0027) */
+#define RT5665_M_MONO_ADC_L1                   (0x1 << 15)
+#define RT5665_M_MONO_ADC_L1_SFT               15
+#define RT5665_M_MONO_ADC_L2                   (0x1 << 14)
+#define RT5665_M_MONO_ADC_L2_SFT               14
+#define RT5665_MONO_ADC_L1_SRC_MASK            (0x1 << 13)
+#define RT5665_MONO_ADC_L1_SRC_SFT             13
+#define RT5665_MONO_ADC_L2_SRC_MASK            (0x1 << 12)
+#define RT5665_MONO_ADC_L2_SRC_SFT             12
+#define RT5665_MONO_ADC_L_SRC_MASK             (0x3 << 10)
+#define RT5665_MONO_ADC_L_SRC_SFT              10
+#define RT5665_MONO_DD_L_SRC_MASK              (0x1 << 9)
+#define RT5665_MONO_DD_L_SRC_SFT               9
+#define RT5665_MONO_DMIC_L_SRC_MASK            (0x1 << 8)
+#define RT5665_MONO_DMIC_L_SRC_SFT             8
+#define RT5665_M_MONO_ADC_R1                   (0x1 << 7)
+#define RT5665_M_MONO_ADC_R1_SFT               7
+#define RT5665_M_MONO_ADC_R2                   (0x1 << 6)
+#define RT5665_M_MONO_ADC_R2_SFT               6
+#define RT5665_MONO_ADC_R1_SRC_MASK            (0x1 << 5)
+#define RT5665_MONO_ADC_R1_SRC_SFT             5
+#define RT5665_MONO_ADC_R2_SRC_MASK            (0x1 << 4)
+#define RT5665_MONO_ADC_R2_SRC_SFT             4
+#define RT5665_MONO_ADC_R_SRC_MASK             (0x3 << 2)
+#define RT5665_MONO_ADC_R_SRC_SFT              2
+#define RT5665_MONO_DD_R_SRC_MASK              (0x1 << 1)
+#define RT5665_MONO_DD_R_SRC_SFT               1
+#define RT5665_MONO_DMIC_R_SRC_MASK            0x1
+#define RT5665_MONO_DMIC_R_SRC_SFT             0
+
+/* Stereo2 ADC Mixer Control (0x0028) */
+#define RT5665_M_STO2_ADC_L1                   (0x1 << 15)
+#define RT5665_M_STO2_ADC_L1_UN                        (0x0 << 15)
+#define RT5665_M_STO2_ADC_L1_SFT               15
+#define RT5665_M_STO2_ADC_L2                   (0x1 << 14)
+#define RT5665_M_STO2_ADC_L2_SFT               14
+#define RT5665_STO2_ADC1L_SRC_MASK             (0x1 << 13)
+#define RT5665_STO2_ADC1L_SRC_SFT              13
+#define RT5665_STO2_ADC1_SRC_ADC               (0x1 << 13)
+#define RT5665_STO2_ADC1_SRC_DACMIX            (0x0 << 13)
+#define RT5665_STO2_ADC2L_SRC_MASK             (0x1 << 12)
+#define RT5665_STO2_ADC2L_SRC_SFT              12
+#define RT5665_STO2_ADCL_SRC_MASK              (0x3 << 10)
+#define RT5665_STO2_ADCL_SRC_SFT               10
+#define RT5665_STO2_DD_L_SRC_MASK              (0x1 << 9)
+#define RT5665_STO2_DD_L_SRC_SFT               9
+#define RT5665_STO2_DMIC_SRC_MASK              (0x1 << 8)
+#define RT5665_STO2_DMIC_SRC_SFT               8
+#define RT5665_STO2_DMIC_SRC_DMIC2             (0x1 << 8)
+#define RT5665_STO2_DMIC_SRC_DMIC1             (0x0 << 8)
+#define RT5665_M_STO2_ADC_R1                   (0x1 << 7)
+#define RT5665_M_STO2_ADC_R1_UN                        (0x0 << 7)
+#define RT5665_M_STO2_ADC_R1_SFT               7
+#define RT5665_M_STO2_ADC_R2                   (0x1 << 6)
+#define RT5665_M_STO2_ADC_R2_SFT               6
+#define RT5665_STO2_ADC1R_SRC_MASK             (0x1 << 5)
+#define RT5665_STO2_ADC1R_SRC_SFT              5
+#define RT5665_STO2_ADC2R_SRC_MASK             (0x1 << 4)
+#define RT5665_STO2_ADC2R_SRC_SFT              4
+#define RT5665_STO2_ADCR_SRC_MASK              (0x3 << 2)
+#define RT5665_STO2_ADCR_SRC_SFT               2
+#define RT5665_STO2_DD_R_SRC_MASK              (0x1 << 1)
+#define RT5665_STO2_DD_R_SRC_SFT               1
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5665_M_ADCMIX_L                      (0x1 << 15)
+#define RT5665_M_ADCMIX_L_SFT                  15
+#define RT5665_M_DAC1_L                                (0x1 << 14)
+#define RT5665_M_DAC1_L_SFT                    14
+#define RT5665_DAC1_R_SEL_MASK                 (0x3 << 10)
+#define RT5665_DAC1_R_SEL_SFT                  10
+#define RT5665_DAC1_L_SEL_MASK                 (0x3 << 8)
+#define RT5665_DAC1_L_SEL_SFT                  8
+#define RT5665_M_ADCMIX_R                      (0x1 << 7)
+#define RT5665_M_ADCMIX_R_SFT                  7
+#define RT5665_M_DAC1_R                                (0x1 << 6)
+#define RT5665_M_DAC1_R_SFT                    6
+
+/* Stereo1 DAC Mixer Control (0x002a) */
+#define RT5665_M_DAC_L1_STO_L                  (0x1 << 15)
+#define RT5665_M_DAC_L1_STO_L_SFT              15
+#define RT5665_G_DAC_L1_STO_L_MASK             (0x1 << 14)
+#define RT5665_G_DAC_L1_STO_L_SFT              14
+#define RT5665_M_DAC_R1_STO_L                  (0x1 << 13)
+#define RT5665_M_DAC_R1_STO_L_SFT              13
+#define RT5665_G_DAC_R1_STO_L_MASK             (0x1 << 12)
+#define RT5665_G_DAC_R1_STO_L_SFT              12
+#define RT5665_M_DAC_L2_STO_L                  (0x1 << 11)
+#define RT5665_M_DAC_L2_STO_L_SFT              11
+#define RT5665_G_DAC_L2_STO_L_MASK             (0x1 << 10)
+#define RT5665_G_DAC_L2_STO_L_SFT              10
+#define RT5665_M_DAC_R2_STO_L                  (0x1 << 9)
+#define RT5665_M_DAC_R2_STO_L_SFT              9
+#define RT5665_G_DAC_R2_STO_L_MASK             (0x1 << 8)
+#define RT5665_G_DAC_R2_STO_L_SFT              8
+#define RT5665_M_DAC_L1_STO_R                  (0x1 << 7)
+#define RT5665_M_DAC_L1_STO_R_SFT              7
+#define RT5665_G_DAC_L1_STO_R_MASK             (0x1 << 6)
+#define RT5665_G_DAC_L1_STO_R_SFT              6
+#define RT5665_M_DAC_R1_STO_R                  (0x1 << 5)
+#define RT5665_M_DAC_R1_STO_R_SFT              5
+#define RT5665_G_DAC_R1_STO_R_MASK             (0x1 << 4)
+#define RT5665_G_DAC_R1_STO_R_SFT              4
+#define RT5665_M_DAC_L2_STO_R                  (0x1 << 3)
+#define RT5665_M_DAC_L2_STO_R_SFT              3
+#define RT5665_G_DAC_L2_STO_R_MASK             (0x1 << 2)
+#define RT5665_G_DAC_L2_STO_R_SFT              2
+#define RT5665_M_DAC_R2_STO_R                  (0x1 << 1)
+#define RT5665_M_DAC_R2_STO_R_SFT              1
+#define RT5665_G_DAC_R2_STO_R_MASK             (0x1)
+#define RT5665_G_DAC_R2_STO_R_SFT              0
+
+/* Mono DAC Mixer Control (0x002b) */
+#define RT5665_M_DAC_L1_MONO_L                 (0x1 << 15)
+#define RT5665_M_DAC_L1_MONO_L_SFT             15
+#define RT5665_G_DAC_L1_MONO_L_MASK            (0x1 << 14)
+#define RT5665_G_DAC_L1_MONO_L_SFT             14
+#define RT5665_M_DAC_R1_MONO_L                 (0x1 << 13)
+#define RT5665_M_DAC_R1_MONO_L_SFT             13
+#define RT5665_G_DAC_R1_MONO_L_MASK            (0x1 << 12)
+#define RT5665_G_DAC_R1_MONO_L_SFT             12
+#define RT5665_M_DAC_L2_MONO_L                 (0x1 << 11)
+#define RT5665_M_DAC_L2_MONO_L_SFT             11
+#define RT5665_G_DAC_L2_MONO_L_MASK            (0x1 << 10)
+#define RT5665_G_DAC_L2_MONO_L_SFT             10
+#define RT5665_M_DAC_R2_MONO_L                 (0x1 << 9)
+#define RT5665_M_DAC_R2_MONO_L_SFT             9
+#define RT5665_G_DAC_R2_MONO_L_MASK            (0x1 << 8)
+#define RT5665_G_DAC_R2_MONO_L_SFT             8
+#define RT5665_M_DAC_L1_MONO_R                 (0x1 << 7)
+#define RT5665_M_DAC_L1_MONO_R_SFT             7
+#define RT5665_G_DAC_L1_MONO_R_MASK            (0x1 << 6)
+#define RT5665_G_DAC_L1_MONO_R_SFT             6
+#define RT5665_M_DAC_R1_MONO_R                 (0x1 << 5)
+#define RT5665_M_DAC_R1_MONO_R_SFT             5
+#define RT5665_G_DAC_R1_MONO_R_MASK            (0x1 << 4)
+#define RT5665_G_DAC_R1_MONO_R_SFT             4
+#define RT5665_M_DAC_L2_MONO_R                 (0x1 << 3)
+#define RT5665_M_DAC_L2_MONO_R_SFT             3
+#define RT5665_G_DAC_L2_MONO_R_MASK            (0x1 << 2)
+#define RT5665_G_DAC_L2_MONO_R_SFT             2
+#define RT5665_M_DAC_R2_MONO_R                 (0x1 << 1)
+#define RT5665_M_DAC_R2_MONO_R_SFT             1
+#define RT5665_G_DAC_R2_MONO_R_MASK            (0x1)
+#define RT5665_G_DAC_R2_MONO_R_SFT             0
+
+/* Stereo2 DAC Mixer Control (0x002c) */
+#define RT5665_M_DAC_L1_STO2_L                 (0x1 << 15)
+#define RT5665_M_DAC_L1_STO2_L_SFT             15
+#define RT5665_G_DAC_L1_STO2_L_MASK            (0x1 << 14)
+#define RT5665_G_DAC_L1_STO2_L_SFT             14
+#define RT5665_M_DAC_L2_STO2_L                 (0x1 << 13)
+#define RT5665_M_DAC_L2_STO2_L_SFT             13
+#define RT5665_G_DAC_L2_STO2_L_MASK            (0x1 << 12)
+#define RT5665_G_DAC_L2_STO2_L_SFT             12
+#define RT5665_M_DAC_L3_STO2_L                 (0x1 << 11)
+#define RT5665_M_DAC_L3_STO2_L_SFT             11
+#define RT5665_G_DAC_L3_STO2_L_MASK            (0x1 << 10)
+#define RT5665_G_DAC_L3_STO2_L_SFT             10
+#define RT5665_M_ST_DAC_L1                     (0x1 << 9)
+#define RT5665_M_ST_DAC_L1_SFT                 9
+#define RT5665_M_ST_DAC_R1                     (0x1 << 8)
+#define RT5665_M_ST_DAC_R1_SFT                 8
+#define RT5665_M_DAC_R1_STO2_R                 (0x1 << 7)
+#define RT5665_M_DAC_R1_STO2_R_SFT             7
+#define RT5665_G_DAC_R1_STO2_R_MASK            (0x1 << 6)
+#define RT5665_G_DAC_R1_STO2_R_SFT             6
+#define RT5665_M_DAC_R2_STO2_R                 (0x1 << 5)
+#define RT5665_M_DAC_R2_STO2_R_SFT             5
+#define RT5665_G_DAC_R2_STO2_R_MASK            (0x1 << 4)
+#define RT5665_G_DAC_R2_STO2_R_SFT             4
+#define RT5665_M_DAC_R3_STO2_R                 (0x1 << 3)
+#define RT5665_M_DAC_R3_STO2_R_SFT             3
+#define RT5665_G_DAC_R3_STO2_R_MASK            (0x1 << 2)
+#define RT5665_G_DAC_R3_STO2_R_SFT             2
+
+/* Analog DAC1 Input Source Control (0x002d) */
+#define RT5665_DAC_MIX_L_MASK                  (0x3 << 12)
+#define RT5665_DAC_MIX_L_SFT                   12
+#define RT5665_DAC_MIX_R_MASK                  (0x3 << 8)
+#define RT5665_DAC_MIX_R_SFT                   8
+#define RT5665_DAC_L1_SRC_MASK                 (0x3 << 4)
+#define RT5665_A_DACL1_SFT                     4
+#define RT5665_DAC_R1_SRC_MASK                 (0x3)
+#define RT5665_A_DACR1_SFT                     0
+
+/* Analog DAC Input Source Control (0x002e) */
+#define RT5665_A_DACL2_SEL                     (0x1 << 4)
+#define RT5665_A_DACL2_SFT                     4
+#define RT5665_A_DACR2_SEL                     (0x1 << 0)
+#define RT5665_A_DACR2_SFT                     0
+
+/* Digital Interface Data Control (0x002f) */
+#define RT5665_IF2_1_ADC_IN_MASK               (0x7 << 12)
+#define RT5665_IF2_1_ADC_IN_SFT                        12
+#define RT5665_IF2_1_DAC_SEL_MASK              (0x3 << 10)
+#define RT5665_IF2_1_DAC_SEL_SFT               10
+#define RT5665_IF2_1_ADC_SEL_MASK              (0x3 << 8)
+#define RT5665_IF2_1_ADC_SEL_SFT               8
+#define RT5665_IF2_2_ADC_IN_MASK               (0x7 << 4)
+#define RT5665_IF2_2_ADC_IN_SFT                        4
+#define RT5665_IF2_2_DAC_SEL_MASK              (0x3 << 2)
+#define RT5665_IF2_2_DAC_SEL_SFT               2
+#define RT5665_IF2_2_ADC_SEL_MASK              (0x3 << 0)
+#define RT5665_IF2_2_ADC_SEL_SFT               0
+
+/* Digital Interface Data Control (0x0030) */
+#define RT5665_IF3_ADC_IN_MASK                 (0x7 << 4)
+#define RT5665_IF3_ADC_IN_SFT                  4
+#define RT5665_IF3_DAC_SEL_MASK                        (0x3 << 2)
+#define RT5665_IF3_DAC_SEL_SFT                 2
+#define RT5665_IF3_ADC_SEL_MASK                        (0x3 << 0)
+#define RT5665_IF3_ADC_SEL_SFT                 0
+
+/* PDM Output Control (0x0031) */
+#define RT5665_M_PDM1_L                                (0x1 << 14)
+#define RT5665_M_PDM1_L_SFT                    14
+#define RT5665_M_PDM1_R                                (0x1 << 12)
+#define RT5665_M_PDM1_R_SFT                    12
+#define RT5665_PDM1_L_MASK                     (0x3 << 10)
+#define RT5665_PDM1_L_SFT                      10
+#define RT5665_PDM1_R_MASK                     (0x3 << 8)
+#define RT5665_PDM1_R_SFT                      8
+#define RT5665_PDM1_BUSY                       (0x1 << 6)
+#define RT5665_PDM_PATTERN                     (0x1 << 5)
+#define RT5665_PDM_GAIN                                (0x1 << 4)
+#define RT5665_LRCK_PDM_PI2C                   (0x1 << 3)
+#define RT5665_PDM_DIV_MASK                    (0x3)
+
+/*S/PDIF Output Control (0x0036) */
+#define RT5665_SPDIF_SEL_MASK                  (0x3 << 0)
+#define RT5665_SPDIF_SEL_SFT                   0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5665_M_CBJ_RM1_L                     (0x1 << 7)
+#define RT5665_M_CBJ_RM1_L_SFT                 7
+#define RT5665_M_BST1_RM1_L                    (0x1 << 5)
+#define RT5665_M_BST1_RM1_L_SFT                        5
+#define RT5665_M_BST2_RM1_L                    (0x1 << 4)
+#define RT5665_M_BST2_RM1_L_SFT                        4
+#define RT5665_M_BST3_RM1_L                    (0x1 << 3)
+#define RT5665_M_BST3_RM1_L_SFT                        3
+#define RT5665_M_BST4_RM1_L                    (0x1 << 2)
+#define RT5665_M_BST4_RM1_L_SFT                        2
+#define RT5665_M_INL_RM1_L                     (0x1 << 1)
+#define RT5665_M_INL_RM1_L_SFT                 1
+#define RT5665_M_INR_RM1_L                     (0x1)
+#define RT5665_M_INR_RM1_L_SFT                 0
+
+/* REC Right Mixer Control 2 (0x003e) */
+#define RT5665_M_AEC_REF_RM1_R                 (0x1 << 7)
+#define RT5665_M_AEC_REF_RM1_R_SFT             7
+#define RT5665_M_BST1_RM1_R                    (0x1 << 5)
+#define RT5665_M_BST1_RM1_R_SFT                        5
+#define RT5665_M_BST2_RM1_R                    (0x1 << 4)
+#define RT5665_M_BST2_RM1_R_SFT                        4
+#define RT5665_M_BST3_RM1_R                    (0x1 << 3)
+#define RT5665_M_BST3_RM1_R_SFT                        3
+#define RT5665_M_BST4_RM1_R                    (0x1 << 2)
+#define RT5665_M_BST4_RM1_R_SFT                        2
+#define RT5665_M_INR_RM1_R                     (0x1 << 1)
+#define RT5665_M_INR_RM1_R_SFT                 1
+#define RT5665_M_MONOVOL_RM1_R                 (0x1)
+#define RT5665_M_MONOVOL_RM1_R_SFT             0
+
+/* REC Mixer 2 Left Control 2 (0x0041) */
+#define RT5665_M_CBJ_RM2_L                     (0x1 << 7)
+#define RT5665_M_CBJ_RM2_L_SFT                 7
+#define RT5665_M_BST1_RM2_L                    (0x1 << 5)
+#define RT5665_M_BST1_RM2_L_SFT                        5
+#define RT5665_M_BST2_RM2_L                    (0x1 << 4)
+#define RT5665_M_BST2_RM2_L_SFT                        4
+#define RT5665_M_BST3_RM2_L                    (0x1 << 3)
+#define RT5665_M_BST3_RM2_L_SFT                        3
+#define RT5665_M_BST4_RM2_L                    (0x1 << 2)
+#define RT5665_M_BST4_RM2_L_SFT                        2
+#define RT5665_M_INL_RM2_L                     (0x1 << 1)
+#define RT5665_M_INL_RM2_L_SFT                 1
+#define RT5665_M_INR_RM2_L                     (0x1)
+#define RT5665_M_INR_RM2_L_SFT                 0
+
+/* REC Mixer 2 Right Control 2 (0x0043) */
+#define RT5665_M_MONOVOL_RM2_R                 (0x1 << 7)
+#define RT5665_M_MONOVOL_RM2_R_SFT             7
+#define RT5665_M_BST1_RM2_R                    (0x1 << 5)
+#define RT5665_M_BST1_RM2_R_SFT                        5
+#define RT5665_M_BST2_RM2_R                    (0x1 << 4)
+#define RT5665_M_BST2_RM2_R_SFT                        4
+#define RT5665_M_BST3_RM2_R                    (0x1 << 3)
+#define RT5665_M_BST3_RM2_R_SFT                        3
+#define RT5665_M_BST4_RM2_R                    (0x1 << 2)
+#define RT5665_M_BST4_RM2_R_SFT                        2
+#define RT5665_M_INL_RM2_R                     (0x1 << 1)
+#define RT5665_M_INL_RM2_R_SFT                 1
+#define RT5665_M_INR_RM2_R                     (0x1)
+#define RT5665_M_INR_RM2_R_SFT                 0
+
+/* SPK Left Mixer Control (0x0046) */
+#define RT5665_M_BST3_SM_L                     (0x1 << 4)
+#define RT5665_M_BST3_SM_L_SFT                 4
+#define RT5665_M_IN_R_SM_L                     (0x1 << 3)
+#define RT5665_M_IN_R_SM_L_SFT                 3
+#define RT5665_M_IN_L_SM_L                     (0x1 << 2)
+#define RT5665_M_IN_L_SM_L_SFT                 2
+#define RT5665_M_BST1_SM_L                     (0x1 << 1)
+#define RT5665_M_BST1_SM_L_SFT                 1
+#define RT5665_M_DAC_L2_SM_L                   (0x1)
+#define RT5665_M_DAC_L2_SM_L_SFT               0
+
+/* SPK Right Mixer Control (0x0047) */
+#define RT5665_M_BST3_SM_R                     (0x1 << 4)
+#define RT5665_M_BST3_SM_R_SFT                 4
+#define RT5665_M_IN_R_SM_R                     (0x1 << 3)
+#define RT5665_M_IN_R_SM_R_SFT                 3
+#define RT5665_M_IN_L_SM_R                     (0x1 << 2)
+#define RT5665_M_IN_L_SM_R_SFT                 2
+#define RT5665_M_BST4_SM_R                     (0x1 << 1)
+#define RT5665_M_BST4_SM_R_SFT                 1
+#define RT5665_M_DAC_R2_SM_R                   (0x1)
+#define RT5665_M_DAC_R2_SM_R_SFT               0
+
+/* SPO Amp Input and Gain Control (0x0048) */
+#define RT5665_M_DAC_L2_SPKOMIX                        (0x1 << 13)
+#define RT5665_M_DAC_L2_SPKOMIX_SFT            13
+#define RT5665_M_SPKVOLL_SPKOMIX               (0x1 << 12)
+#define RT5665_M_SPKVOLL_SPKOMIX_SFT           12
+#define RT5665_M_DAC_R2_SPKOMIX                        (0x1 << 9)
+#define RT5665_M_DAC_R2_SPKOMIX_SFT            9
+#define RT5665_M_SPKVOLR_SPKOMIX               (0x1 << 8)
+#define RT5665_M_SPKVOLR_SPKOMIX_SFT           8
+
+/* MONOMIX Input and Gain Control (0x004b) */
+#define RT5665_G_MONOVOL_MA                    (0x1 << 10)
+#define RT5665_G_MONOVOL_MA_SFT                        10
+#define RT5665_M_MONOVOL_MA                    (0x1 << 9)
+#define RT5665_M_MONOVOL_MA_SFT                        9
+#define RT5665_M_DAC_L2_MA                     (0x1 << 8)
+#define RT5665_M_DAC_L2_MA_SFT                 8
+#define RT5665_M_BST3_MM                       (0x1 << 4)
+#define RT5665_M_BST3_MM_SFT                   4
+#define RT5665_M_BST2_MM                       (0x1 << 3)
+#define RT5665_M_BST2_MM_SFT                   3
+#define RT5665_M_BST1_MM                       (0x1 << 2)
+#define RT5665_M_BST1_MM_SFT                   2
+#define RT5665_M_RECMIC2L_MM                   (0x1 << 1)
+#define RT5665_M_RECMIC2L_MM_SFT               1
+#define RT5665_M_DAC_L2_MM                     (0x1)
+#define RT5665_M_DAC_L2_MM_SFT                 0
+
+/* Output Left Mixer Control 1 (0x004d) */
+#define RT5665_G_BST3_OM_L_MASK                        (0x7 << 12)
+#define RT5665_G_BST3_OM_L_SFT                 12
+#define RT5665_G_BST2_OM_L_MASK                        (0x7 << 9)
+#define RT5665_G_BST2_OM_L_SFT                 9
+#define RT5665_G_BST1_OM_L_MASK                        (0x7 << 6)
+#define RT5665_G_BST1_OM_L_SFT                 6
+#define RT5665_G_IN_L_OM_L_MASK                        (0x7 << 3)
+#define RT5665_G_IN_L_OM_L_SFT                 3
+#define RT5665_G_DAC_L2_OM_L_MASK              (0x7 << 0)
+#define RT5665_G_DAC_L2_OM_L_SFT               0
+
+/* Output Left Mixer Input Control (0x004e) */
+#define RT5665_M_BST3_OM_L                     (0x1 << 4)
+#define RT5665_M_BST3_OM_L_SFT                 4
+#define RT5665_M_BST2_OM_L                     (0x1 << 3)
+#define RT5665_M_BST2_OM_L_SFT                 3
+#define RT5665_M_BST1_OM_L                     (0x1 << 2)
+#define RT5665_M_BST1_OM_L_SFT                 2
+#define RT5665_M_IN_L_OM_L                     (0x1 << 1)
+#define RT5665_M_IN_L_OM_L_SFT                 1
+#define RT5665_M_DAC_L2_OM_L                   (0x1)
+#define RT5665_M_DAC_L2_OM_L_SFT               0
+
+/* Output Right Mixer Input Control (0x0050) */
+#define RT5665_M_BST4_OM_R                     (0x1 << 4)
+#define RT5665_M_BST4_OM_R_SFT                 4
+#define RT5665_M_BST3_OM_R                     (0x1 << 3)
+#define RT5665_M_BST3_OM_R_SFT                 3
+#define RT5665_M_BST2_OM_R                     (0x1 << 2)
+#define RT5665_M_BST2_OM_R_SFT                 2
+#define RT5665_M_IN_R_OM_R                     (0x1 << 1)
+#define RT5665_M_IN_R_OM_R_SFT                 1
+#define RT5665_M_DAC_R2_OM_R                   (0x1)
+#define RT5665_M_DAC_R2_OM_R_SFT               0
+
+/* LOUT Mixer Control (0x0052) */
+#define RT5665_M_DAC_L2_LM                     (0x1 << 15)
+#define RT5665_M_DAC_L2_LM_SFT                 15
+#define RT5665_M_DAC_R2_LM                     (0x1 << 14)
+#define RT5665_M_DAC_R2_LM_SFT                 14
+#define RT5665_M_OV_L_LM                       (0x1 << 13)
+#define RT5665_M_OV_L_LM_SFT                   13
+#define RT5665_M_OV_R_LM                       (0x1 << 12)
+#define RT5665_M_OV_R_LM_SFT                   12
+#define RT5665_LOUT_BST_SFT                    11
+#define RT5665_LOUT_DF                         (0x1 << 11)
+#define RT5665_LOUT_DF_SFT                     11
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5665_PWR_I2S1_1                      (0x1 << 15)
+#define RT5665_PWR_I2S1_1_BIT                  15
+#define RT5665_PWR_I2S1_2                      (0x1 << 14)
+#define RT5665_PWR_I2S1_2_BIT                  14
+#define RT5665_PWR_I2S2_1                      (0x1 << 13)
+#define RT5665_PWR_I2S2_1_BIT                  13
+#define RT5665_PWR_I2S2_2                      (0x1 << 12)
+#define RT5665_PWR_I2S2_2_BIT                  12
+#define RT5665_PWR_DAC_L1                      (0x1 << 11)
+#define RT5665_PWR_DAC_L1_BIT                  11
+#define RT5665_PWR_DAC_R1                      (0x1 << 10)
+#define RT5665_PWR_DAC_R1_BIT                  10
+#define RT5665_PWR_I2S3                                (0x1 << 9)
+#define RT5665_PWR_I2S3_BIT                    9
+#define RT5665_PWR_LDO                         (0x1 << 8)
+#define RT5665_PWR_LDO_BIT                     8
+#define RT5665_PWR_DAC_L2                      (0x1 << 7)
+#define RT5665_PWR_DAC_L2_BIT                  7
+#define RT5665_PWR_DAC_R2                      (0x1 << 6)
+#define RT5665_PWR_DAC_R2_BIT                  6
+#define RT5665_PWR_ADC_L1                      (0x1 << 4)
+#define RT5665_PWR_ADC_L1_BIT                  4
+#define RT5665_PWR_ADC_R1                      (0x1 << 3)
+#define RT5665_PWR_ADC_R1_BIT                  3
+#define RT5665_PWR_ADC_L2                      (0x1 << 2)
+#define RT5665_PWR_ADC_L2_BIT                  2
+#define RT5665_PWR_ADC_R2                      (0x1 << 1)
+#define RT5665_PWR_ADC_R2_BIT                  1
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5665_PWR_ADC_S1F                     (0x1 << 15)
+#define RT5665_PWR_ADC_S1F_BIT                 15
+#define RT5665_PWR_ADC_S2F                     (0x1 << 14)
+#define RT5665_PWR_ADC_S2F_BIT                 14
+#define RT5665_PWR_ADC_MF_L                    (0x1 << 13)
+#define RT5665_PWR_ADC_MF_L_BIT                        13
+#define RT5665_PWR_ADC_MF_R                    (0x1 << 12)
+#define RT5665_PWR_ADC_MF_R_BIT                        12
+#define RT5665_PWR_DAC_S2F                     (0x1 << 11)
+#define RT5665_PWR_DAC_S2F_BIT                 11
+#define RT5665_PWR_DAC_S1F                     (0x1 << 10)
+#define RT5665_PWR_DAC_S1F_BIT                 10
+#define RT5665_PWR_DAC_MF_L                    (0x1 << 9)
+#define RT5665_PWR_DAC_MF_L_BIT                        9
+#define RT5665_PWR_DAC_MF_R                    (0x1 << 8)
+#define RT5665_PWR_DAC_MF_R_BIT                        8
+#define RT5665_PWR_PDM1                                (0x1 << 7)
+#define RT5665_PWR_PDM1_BIT                    7
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5665_PWR_VREF1                       (0x1 << 15)
+#define RT5665_PWR_VREF1_BIT                   15
+#define RT5665_PWR_FV1                         (0x1 << 14)
+#define RT5665_PWR_FV1_BIT                     14
+#define RT5665_PWR_VREF2                       (0x1 << 13)
+#define RT5665_PWR_VREF2_BIT                   13
+#define RT5665_PWR_FV2                         (0x1 << 12)
+#define RT5665_PWR_FV2_BIT                     12
+#define RT5665_PWR_VREF3                       (0x1 << 11)
+#define RT5665_PWR_VREF3_BIT                   11
+#define RT5665_PWR_FV3                         (0x1 << 10)
+#define RT5665_PWR_FV3_BIT                     10
+#define RT5665_PWR_MB                          (0x1 << 9)
+#define RT5665_PWR_MB_BIT                      9
+#define RT5665_PWR_LM                          (0x1 << 8)
+#define RT5665_PWR_LM_BIT                      8
+#define RT5665_PWR_BG                          (0x1 << 7)
+#define RT5665_PWR_BG_BIT                      7
+#define RT5665_PWR_MA                          (0x1 << 6)
+#define RT5665_PWR_MA_BIT                      6
+#define RT5665_PWR_HA_L                                (0x1 << 5)
+#define RT5665_PWR_HA_L_BIT                    5
+#define RT5665_PWR_HA_R                                (0x1 << 4)
+#define RT5665_PWR_HA_R_BIT                    4
+#define RT5665_HP_DRIVER_MASK                  (0x3 << 2)
+#define RT5665_HP_DRIVER_1X                    (0x0 << 2)
+#define RT5665_HP_DRIVER_3X                    (0x1 << 2)
+#define RT5665_HP_DRIVER_5X                    (0x2 << 2)
+#define RT5665_LDO1_DVO_MASK                   (0x3)
+#define RT5665_LDO1_DVO_09                     (0x0)
+#define RT5665_LDO1_DVO_10                     (0x1)
+#define RT5665_LDO1_DVO_12                     (0x2)
+#define RT5665_LDO1_DVO_14                     (0x3)
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5665_PWR_BST1                                (0x1 << 15)
+#define RT5665_PWR_BST1_BIT                    15
+#define RT5665_PWR_BST2                                (0x1 << 14)
+#define RT5665_PWR_BST2_BIT                    14
+#define RT5665_PWR_BST3                                (0x1 << 13)
+#define RT5665_PWR_BST3_BIT                    13
+#define RT5665_PWR_BST4                                (0x1 << 12)
+#define RT5665_PWR_BST4_BIT                    12
+#define RT5665_PWR_MB1                         (0x1 << 11)
+#define RT5665_PWR_MB1_PWR_DOWN                        (0x0 << 11)
+#define RT5665_PWR_MB1_BIT                     11
+#define RT5665_PWR_MB2                         (0x1 << 10)
+#define RT5665_PWR_MB2_PWR_DOWN                        (0x0 << 10)
+#define RT5665_PWR_MB2_BIT                     10
+#define RT5665_PWR_MB3                         (0x1 << 9)
+#define RT5665_PWR_MB3_BIT                     9
+#define RT5665_PWR_BST1_P                      (0x1 << 7)
+#define RT5665_PWR_BST1_P_BIT                  7
+#define RT5665_PWR_BST2_P                      (0x1 << 6)
+#define RT5665_PWR_BST2_P_BIT                  6
+#define RT5665_PWR_BST3_P                      (0x1 << 5)
+#define RT5665_PWR_BST3_P_BIT                  5
+#define RT5665_PWR_BST4_P                      (0x1 << 4)
+#define RT5665_PWR_BST4_P_BIT                  4
+#define RT5665_PWR_JD1                         (0x1 << 3)
+#define RT5665_PWR_JD1_BIT                     3
+#define RT5665_PWR_JD2                         (0x1 << 2)
+#define RT5665_PWR_JD2_BIT                     2
+#define RT5665_PWR_RM1_L                       (0x1 << 1)
+#define RT5665_PWR_RM1_L_BIT                   1
+#define RT5665_PWR_RM1_R                       (0x1)
+#define RT5665_PWR_RM1_R_BIT                   0
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5665_PWR_CBJ                         (0x1 << 9)
+#define RT5665_PWR_CBJ_BIT                     9
+#define RT5665_PWR_BST_L                       (0x1 << 8)
+#define RT5665_PWR_BST_L_BIT                   8
+#define RT5665_PWR_BST_R                       (0x1 << 7)
+#define RT5665_PWR_BST_R_BIT                   7
+#define RT5665_PWR_PLL                         (0x1 << 6)
+#define RT5665_PWR_PLL_BIT                     6
+#define RT5665_PWR_LDO2                                (0x1 << 2)
+#define RT5665_PWR_LDO2_BIT                    2
+#define RT5665_PWR_SVD                         (0x1 << 1)
+#define RT5665_PWR_SVD_BIT                     1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5665_PWR_RM2_L                       (0x1 << 15)
+#define RT5665_PWR_RM2_L_BIT                   15
+#define RT5665_PWR_RM2_R                       (0x1 << 14)
+#define RT5665_PWR_RM2_R_BIT                   14
+#define RT5665_PWR_OM_L                                (0x1 << 13)
+#define RT5665_PWR_OM_L_BIT                    13
+#define RT5665_PWR_OM_R                                (0x1 << 12)
+#define RT5665_PWR_OM_R_BIT                    12
+#define RT5665_PWR_MM                          (0x1 << 11)
+#define RT5665_PWR_MM_BIT                      11
+#define RT5665_PWR_AEC_REF                     (0x1 << 6)
+#define RT5665_PWR_AEC_REF_BIT                 6
+#define RT5665_PWR_STO1_DAC_L                  (0x1 << 5)
+#define RT5665_PWR_STO1_DAC_L_BIT              5
+#define RT5665_PWR_STO1_DAC_R                  (0x1 << 4)
+#define RT5665_PWR_STO1_DAC_R_BIT              4
+#define RT5665_PWR_MONO_DAC_L                  (0x1 << 3)
+#define RT5665_PWR_MONO_DAC_L_BIT              3
+#define RT5665_PWR_MONO_DAC_R                  (0x1 << 2)
+#define RT5665_PWR_MONO_DAC_R_BIT              2
+#define RT5665_PWR_STO2_DAC_L                  (0x1 << 1)
+#define RT5665_PWR_STO2_DAC_L_BIT              1
+#define RT5665_PWR_STO2_DAC_R                  (0x1)
+#define RT5665_PWR_STO2_DAC_R_BIT              0
+
+/* Power Management for Volume (0x0067) */
+#define RT5665_PWR_OV_L                                (0x1 << 13)
+#define RT5665_PWR_OV_L_BIT                    13
+#define RT5665_PWR_OV_R                                (0x1 << 12)
+#define RT5665_PWR_OV_R_BIT                    12
+#define RT5665_PWR_IN_L                                (0x1 << 9)
+#define RT5665_PWR_IN_L_BIT                    9
+#define RT5665_PWR_IN_R                                (0x1 << 8)
+#define RT5665_PWR_IN_R_BIT                    8
+#define RT5665_PWR_MV                          (0x1 << 7)
+#define RT5665_PWR_MV_BIT                      7
+#define RT5665_PWR_MIC_DET                     (0x1 << 5)
+#define RT5665_PWR_MIC_DET_BIT                 5
+
+/* (0x006b) */
+#define RT5665_SYS_CLK_DET                     15
+#define RT5665_HP_CLK_DET                      14
+#define RT5665_MONO_CLK_DET                    13
+#define RT5665_LOUT_CLK_DET                    12
+#define RT5665_POW_CLK_DET                     0
+
+/* Digital Microphone Control 1 (0x006e) */
+#define RT5665_DMIC_1_EN_MASK                  (0x1 << 15)
+#define RT5665_DMIC_1_EN_SFT                   15
+#define RT5665_DMIC_1_DIS                      (0x0 << 15)
+#define RT5665_DMIC_1_EN                       (0x1 << 15)
+#define RT5665_DMIC_2_EN_MASK                  (0x1 << 14)
+#define RT5665_DMIC_2_EN_SFT                   14
+#define RT5665_DMIC_2_DIS                      (0x0 << 14)
+#define RT5665_DMIC_2_EN                       (0x1 << 14)
+#define RT5665_DMIC_2_DP_MASK                  (0x1 << 9)
+#define RT5665_DMIC_2_DP_SFT                   9
+#define RT5665_DMIC_2_DP_GPIO5                 (0x0 << 9)
+#define RT5665_DMIC_2_DP_IN2P                  (0x1 << 9)
+#define RT5665_DMIC_CLK_MASK                   (0x7 << 5)
+#define RT5665_DMIC_CLK_SFT                    5
+#define RT5665_DMIC_1_DP_MASK                  (0x1 << 1)
+#define RT5665_DMIC_1_DP_SFT                   1
+#define RT5665_DMIC_1_DP_GPIO4                 (0x0 << 1)
+#define RT5665_DMIC_1_DP_IN2N                  (0x1 << 1)
+
+
+/* Digital Microphone Control 1 (0x006f) */
+#define RT5665_DMIC_2L_LH_MASK                 (0x1 << 3)
+#define RT5665_DMIC_2L_LH_SFT                  3
+#define RT5665_DMIC_2L_LH_RISING               (0x0 << 3)
+#define RT5665_DMIC_2L_LH_FALLING              (0x1 << 3)
+#define RT5665_DMIC_2R_LH_MASK                 (0x1 << 2)
+#define RT5665_DMIC_2R_LH_SFT                  2
+#define RT5665_DMIC_2R_LH_RISING               (0x0 << 2)
+#define RT5665_DMIC_2R_LH_FALLING              (0x1 << 2)
+#define RT5665_DMIC_1L_LH_MASK                 (0x1 << 1)
+#define RT5665_DMIC_1L_LH_SFT                  1
+#define RT5665_DMIC_1L_LH_RISING               (0x0 << 1)
+#define RT5665_DMIC_1L_LH_FALLING              (0x1 << 1)
+#define RT5665_DMIC_1R_LH_MASK                 (0x1 << 0)
+#define RT5665_DMIC_1R_LH_SFT                  0
+#define RT5665_DMIC_1R_LH_RISING               (0x0)
+#define RT5665_DMIC_1R_LH_FALLING              (0x1)
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */
+#define RT5665_I2S_MS_MASK                     (0x1 << 15)
+#define RT5665_I2S_MS_SFT                      15
+#define RT5665_I2S_MS_M                                (0x0 << 15)
+#define RT5665_I2S_MS_S                                (0x1 << 15)
+#define RT5665_I2S_PIN_CFG_MASK                        (0x1 << 14)
+#define RT5665_I2S_PIN_CFG_SFT                 14
+#define RT5665_I2S_CLK_SEL_MASK                        (0x1 << 11)
+#define RT5665_I2S_CLK_SEL_SFT                 11
+#define RT5665_I2S_BP_MASK                     (0x1 << 8)
+#define RT5665_I2S_BP_SFT                      8
+#define RT5665_I2S_BP_NOR                      (0x0 << 8)
+#define RT5665_I2S_BP_INV                      (0x1 << 8)
+#define RT5665_I2S_DL_MASK                     (0x3 << 4)
+#define RT5665_I2S_DL_SFT                      4
+#define RT5665_I2S_DL_16                       (0x0 << 4)
+#define RT5665_I2S_DL_20                       (0x1 << 4)
+#define RT5665_I2S_DL_24                       (0x2 << 4)
+#define RT5665_I2S_DL_8                                (0x3 << 4)
+#define RT5665_I2S_DF_MASK                     (0x7)
+#define RT5665_I2S_DF_SFT                      0
+#define RT5665_I2S_DF_I2S                      (0x0)
+#define RT5665_I2S_DF_LEFT                     (0x1)
+#define RT5665_I2S_DF_PCM_A                    (0x2)
+#define RT5665_I2S_DF_PCM_B                    (0x3)
+#define RT5665_I2S_DF_PCM_A_N                  (0x6)
+#define RT5665_I2S_DF_PCM_B_N                  (0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5665_I2S_PD1_MASK                    (0x7 << 12)
+#define RT5665_I2S_PD1_SFT                     12
+#define RT5665_I2S_PD1_1                       (0x0 << 12)
+#define RT5665_I2S_PD1_2                       (0x1 << 12)
+#define RT5665_I2S_PD1_3                       (0x2 << 12)
+#define RT5665_I2S_PD1_4                       (0x3 << 12)
+#define RT5665_I2S_PD1_6                       (0x4 << 12)
+#define RT5665_I2S_PD1_8                       (0x5 << 12)
+#define RT5665_I2S_PD1_12                      (0x6 << 12)
+#define RT5665_I2S_PD1_16                      (0x7 << 12)
+#define RT5665_I2S_M_PD2_MASK                  (0x7 << 8)
+#define RT5665_I2S_M_PD2_SFT                   8
+#define RT5665_I2S_M_PD2_1                     (0x0 << 8)
+#define RT5665_I2S_M_PD2_2                     (0x1 << 8)
+#define RT5665_I2S_M_PD2_3                     (0x2 << 8)
+#define RT5665_I2S_M_PD2_4                     (0x3 << 8)
+#define RT5665_I2S_M_PD2_6                     (0x4 << 8)
+#define RT5665_I2S_M_PD2_8                     (0x5 << 8)
+#define RT5665_I2S_M_PD2_12                    (0x6 << 8)
+#define RT5665_I2S_M_PD2_16                    (0x7 << 8)
+#define RT5665_I2S_CLK_SRC_MASK                        (0x3 << 4)
+#define RT5665_I2S_CLK_SRC_SFT                 4
+#define RT5665_I2S_CLK_SRC_MCLK                        (0x0 << 4)
+#define RT5665_I2S_CLK_SRC_PLL1                        (0x1 << 4)
+#define RT5665_I2S_CLK_SRC_RCCLK               (0x2 << 4)
+#define RT5665_DAC_OSR_MASK                    (0x3 << 2)
+#define RT5665_DAC_OSR_SFT                     2
+#define RT5665_DAC_OSR_128                     (0x0 << 2)
+#define RT5665_DAC_OSR_64                      (0x1 << 2)
+#define RT5665_DAC_OSR_32                      (0x2 << 2)
+#define RT5665_ADC_OSR_MASK                    (0x3)
+#define RT5665_ADC_OSR_SFT                     0
+#define RT5665_ADC_OSR_128                     (0x0)
+#define RT5665_ADC_OSR_64                      (0x1)
+#define RT5665_ADC_OSR_32                      (0x2)
+
+/* ADC/DAC Clock Control 2 (0x0074) */
+#define RT5665_I2S_BCLK_MS2_MASK               (0x1 << 15)
+#define RT5665_I2S_BCLK_MS2_SFT                        15
+#define RT5665_I2S_BCLK_MS2_32                 (0x0 << 15)
+#define RT5665_I2S_BCLK_MS2_64                 (0x1 << 15)
+#define RT5665_I2S_PD2_MASK                    (0x7 << 12)
+#define RT5665_I2S_PD2_SFT                     12
+#define RT5665_I2S_PD2_1                       (0x0 << 12)
+#define RT5665_I2S_PD2_2                       (0x1 << 12)
+#define RT5665_I2S_PD2_3                       (0x2 << 12)
+#define RT5665_I2S_PD2_4                       (0x3 << 12)
+#define RT5665_I2S_PD2_6                       (0x4 << 12)
+#define RT5665_I2S_PD2_8                       (0x5 << 12)
+#define RT5665_I2S_PD2_12                      (0x6 << 12)
+#define RT5665_I2S_PD2_16                      (0x7 << 12)
+#define RT5665_I2S_BCLK_MS3_MASK               (0x1 << 11)
+#define RT5665_I2S_BCLK_MS3_SFT                        11
+#define RT5665_I2S_BCLK_MS3_32                 (0x0 << 11)
+#define RT5665_I2S_BCLK_MS3_64                 (0x1 << 11)
+#define RT5665_I2S_PD3_MASK                    (0x7 << 8)
+#define RT5665_I2S_PD3_SFT                     8
+#define RT5665_I2S_PD3_1                       (0x0 << 8)
+#define RT5665_I2S_PD3_2                       (0x1 << 8)
+#define RT5665_I2S_PD3_3                       (0x2 << 8)
+#define RT5665_I2S_PD3_4                       (0x3 << 8)
+#define RT5665_I2S_PD3_6                       (0x4 << 8)
+#define RT5665_I2S_PD3_8                       (0x5 << 8)
+#define RT5665_I2S_PD3_12                      (0x6 << 8)
+#define RT5665_I2S_PD3_16                      (0x7 << 8)
+#define RT5665_I2S_PD4_MASK                    (0x7 << 4)
+#define RT5665_I2S_PD4_SFT                     4
+#define RT5665_I2S_PD4_1                       (0x0 << 4)
+#define RT5665_I2S_PD4_2                       (0x1 << 4)
+#define RT5665_I2S_PD4_3                       (0x2 << 4)
+#define RT5665_I2S_PD4_4                       (0x3 << 4)
+#define RT5665_I2S_PD4_6                       (0x4 << 4)
+#define RT5665_I2S_PD4_8                       (0x5 << 4)
+#define RT5665_I2S_PD4_12                      (0x6 << 4)
+#define RT5665_I2S_PD4_16                      (0x7 << 4)
+
+/* TDM control 1 (0x0078) */
+#define RT5665_I2S1_MODE_MASK                  (0x1 << 15)
+#define RT5665_I2S1_MODE_I2S                   (0x0 << 15)
+#define RT5665_I2S1_MODE_TDM                   (0x1 << 15)
+#define RT5665_TDM_IN_CH_MASK                  (0x3 << 10)
+#define RT5665_TDM_IN_CH_2                     (0x0 << 10)
+#define RT5665_TDM_IN_CH_4                     (0x1 << 10)
+#define RT5665_TDM_IN_CH_6                     (0x2 << 10)
+#define RT5665_TDM_IN_CH_8                     (0x3 << 10)
+#define RT5665_TDM_OUT_CH_MASK                 (0x3 << 8)
+#define RT5665_TDM_OUT_CH_2                    (0x0 << 8)
+#define RT5665_TDM_OUT_CH_4                    (0x1 << 8)
+#define RT5665_TDM_OUT_CH_6                    (0x2 << 8)
+#define RT5665_TDM_OUT_CH_8                    (0x3 << 8)
+#define RT5665_TDM_IN_LEN_MASK                 (0x3 << 6)
+#define RT5665_TDM_IN_LEN_16                   (0x0 << 6)
+#define RT5665_TDM_IN_LEN_20                   (0x1 << 6)
+#define RT5665_TDM_IN_LEN_24                   (0x2 << 6)
+#define RT5665_TDM_IN_LEN_32                   (0x3 << 6)
+#define RT5665_TDM_OUT_LEN_MASK                        (0x3 << 4)
+#define RT5665_TDM_OUT_LEN_16                  (0x0 << 4)
+#define RT5665_TDM_OUT_LEN_20                  (0x1 << 4)
+#define RT5665_TDM_OUT_LEN_24                  (0x2 << 4)
+#define RT5665_TDM_OUT_LEN_32                  (0x3 << 4)
+
+
+/* TDM control 2 (0x0079) */
+#define RT5665_I2S1_1_DS_ADC_SLOT01_SFT                14
+#define RT5665_I2S1_1_DS_ADC_SLOT23_SFT                12
+#define RT5665_I2S1_1_DS_ADC_SLOT45_SFT                10
+#define RT5665_I2S1_1_DS_ADC_SLOT67_SFT                8
+#define RT5665_I2S1_2_DS_ADC_SLOT01_SFT                6
+#define RT5665_I2S1_2_DS_ADC_SLOT23_SFT                4
+#define RT5665_I2S1_2_DS_ADC_SLOT45_SFT                2
+#define RT5665_I2S1_2_DS_ADC_SLOT67_SFT                0
+
+/* TDM control 3/4 (0x007a) (0x007b) */
+#define RT5665_IF1_ADC1_SEL_SFT                        10
+#define RT5665_IF1_ADC2_SEL_SFT                        9
+#define RT5665_IF1_ADC3_SEL_SFT                        8
+#define RT5665_IF1_ADC4_SEL_SFT                        7
+#define RT5665_TDM_ADC_SEL_SFT                 0
+#define RT5665_TDM_ADC_CTRL_MASK               (0x1f << 0)
+#define RT5665_TDM_ADC_DATA_06                 (0x6 << 0)
+
+/* Global Clock Control (0x0080) */
+#define RT5665_SCLK_SRC_MASK                   (0x3 << 14)
+#define RT5665_SCLK_SRC_SFT                    14
+#define RT5665_SCLK_SRC_MCLK                   (0x0 << 14)
+#define RT5665_SCLK_SRC_PLL1                   (0x1 << 14)
+#define RT5665_SCLK_SRC_RCCLK                  (0x2 << 14)
+#define RT5665_PLL1_SRC_MASK                   (0x7 << 8)
+#define RT5665_PLL1_SRC_SFT                    8
+#define RT5665_PLL1_SRC_MCLK                   (0x0 << 8)
+#define RT5665_PLL1_SRC_BCLK1                  (0x1 << 8)
+#define RT5665_PLL1_SRC_BCLK2                  (0x2 << 8)
+#define RT5665_PLL1_SRC_BCLK3                  (0x3 << 8)
+#define RT5665_PLL1_PD_MASK                    (0x7 << 4)
+#define RT5665_PLL1_PD_SFT                     4
+
+
+#define RT5665_PLL_INP_MAX                     40000000
+#define RT5665_PLL_INP_MIN                     256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5665_PLL_N_MAX                       0x001ff
+#define RT5665_PLL_N_MASK                      (RT5665_PLL_N_MAX << 7)
+#define RT5665_PLL_N_SFT                       7
+#define RT5665_PLL_K_MAX                       0x001f
+#define RT5665_PLL_K_MASK                      (RT5665_PLL_K_MAX)
+#define RT5665_PLL_K_SFT                       0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5665_PLL_M_MAX                       0x00f
+#define RT5665_PLL_M_MASK                      (RT5665_PLL_M_MAX << 12)
+#define RT5665_PLL_M_SFT                       12
+#define RT5665_PLL_M_BP                                (0x1 << 11)
+#define RT5665_PLL_M_BP_SFT                    11
+#define RT5665_PLL_K_BP                                (0x1 << 10)
+#define RT5665_PLL_K_BP_SFT                    10
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5665_I2S3_ASRC_MASK                  (0x1 << 15)
+#define RT5665_I2S3_ASRC_SFT                   15
+#define RT5665_I2S2_ASRC_MASK                  (0x1 << 14)
+#define RT5665_I2S2_ASRC_SFT                   14
+#define RT5665_I2S1_ASRC_MASK                  (0x1 << 13)
+#define RT5665_I2S1_ASRC_SFT                   13
+#define RT5665_DAC_STO1_ASRC_MASK              (0x1 << 12)
+#define RT5665_DAC_STO1_ASRC_SFT               12
+#define RT5665_DAC_STO2_ASRC_MASK              (0x1 << 11)
+#define RT5665_DAC_STO2_ASRC_SFT               11
+#define RT5665_DAC_MONO_L_ASRC_MASK            (0x1 << 10)
+#define RT5665_DAC_MONO_L_ASRC_SFT             10
+#define RT5665_DAC_MONO_R_ASRC_MASK            (0x1 << 9)
+#define RT5665_DAC_MONO_R_ASRC_SFT             9
+#define RT5665_DMIC_STO1_ASRC_MASK             (0x1 << 8)
+#define RT5665_DMIC_STO1_ASRC_SFT              8
+#define RT5665_DMIC_STO2_ASRC_MASK             (0x1 << 7)
+#define RT5665_DMIC_STO2_ASRC_SFT              7
+#define RT5665_DMIC_MONO_L_ASRC_MASK           (0x1 << 6)
+#define RT5665_DMIC_MONO_L_ASRC_SFT            6
+#define RT5665_DMIC_MONO_R_ASRC_MASK           (0x1 << 5)
+#define RT5665_DMIC_MONO_R_ASRC_SFT            5
+#define RT5665_ADC_STO1_ASRC_MASK              (0x1 << 4)
+#define RT5665_ADC_STO1_ASRC_SFT               4
+#define RT5665_ADC_STO2_ASRC_MASK              (0x1 << 3)
+#define RT5665_ADC_STO2_ASRC_SFT               3
+#define RT5665_ADC_MONO_L_ASRC_MASK            (0x1 << 2)
+#define RT5665_ADC_MONO_L_ASRC_SFT             2
+#define RT5665_ADC_MONO_R_ASRC_MASK            (0x1 << 1)
+#define RT5665_ADC_MONO_R_ASRC_SFT             1
+
+/* PLL tracking mode 2 (0x0084)*/
+#define RT5665_DA_STO1_CLK_SEL_MASK            (0x7 << 12)
+#define RT5665_DA_STO1_CLK_SEL_SFT             12
+#define RT5665_DA_STO2_CLK_SEL_MASK            (0x7 << 8)
+#define RT5665_DA_STO2_CLK_SEL_SFT             8
+#define RT5665_DA_MONOL_CLK_SEL_MASK           (0x7 << 4)
+#define RT5665_DA_MONOL_CLK_SEL_SFT            4
+#define RT5665_DA_MONOR_CLK_SEL_MASK           (0x7)
+#define RT5665_DA_MONOR_CLK_SEL_SFT            0
+
+/* PLL tracking mode 3 (0x0085)*/
+#define RT5665_AD_STO1_CLK_SEL_MASK            (0x7 << 12)
+#define RT5665_AD_STO1_CLK_SEL_SFT             12
+#define RT5665_AD_STO2_CLK_SEL_MASK            (0x7 << 8)
+#define RT5665_AD_STO2_CLK_SEL_SFT             8
+#define RT5665_AD_MONOL_CLK_SEL_MASK           (0x7 << 4)
+#define RT5665_AD_MONOL_CLK_SEL_SFT            4
+#define RT5665_AD_MONOR_CLK_SEL_MASK           (0x7)
+#define RT5665_AD_MONOR_CLK_SEL_SFT            0
+
+/* ASRC Control 4 (0x0086) */
+#define RT5665_I2S1_RATE_MASK                  (0xf << 12)
+#define RT5665_I2S1_RATE_SFT                   12
+#define RT5665_I2S2_RATE_MASK                  (0xf << 8)
+#define RT5665_I2S2_RATE_SFT                   8
+#define RT5665_I2S3_RATE_MASK                  (0xf << 4)
+#define RT5665_I2S3_RATE_SFT                   4
+
+/* Depop Mode Control 1 (0x008e) */
+#define RT5665_PUMP_EN                         (0x1 << 3)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5665_DEPOP_MASK                      (0x1 << 13)
+#define RT5665_DEPOP_SFT                       13
+#define RT5665_DEPOP_AUTO                      (0x0 << 13)
+#define RT5665_DEPOP_MAN                       (0x1 << 13)
+#define RT5665_RAMP_MASK                       (0x1 << 12)
+#define RT5665_RAMP_SFT                                12
+#define RT5665_RAMP_DIS                                (0x0 << 12)
+#define RT5665_RAMP_EN                         (0x1 << 12)
+#define RT5665_BPS_MASK                                (0x1 << 11)
+#define RT5665_BPS_SFT                         11
+#define RT5665_BPS_DIS                         (0x0 << 11)
+#define RT5665_BPS_EN                          (0x1 << 11)
+#define RT5665_FAST_UPDN_MASK                  (0x1 << 10)
+#define RT5665_FAST_UPDN_SFT                   10
+#define RT5665_FAST_UPDN_DIS                   (0x0 << 10)
+#define RT5665_FAST_UPDN_EN                    (0x1 << 10)
+#define RT5665_MRES_MASK                       (0x3 << 8)
+#define RT5665_MRES_SFT                                8
+#define RT5665_MRES_15MO                       (0x0 << 8)
+#define RT5665_MRES_25MO                       (0x1 << 8)
+#define RT5665_MRES_35MO                       (0x2 << 8)
+#define RT5665_MRES_45MO                       (0x3 << 8)
+#define RT5665_VLO_MASK                                (0x1 << 7)
+#define RT5665_VLO_SFT                         7
+#define RT5665_VLO_3V                          (0x0 << 7)
+#define RT5665_VLO_32V                         (0x1 << 7)
+#define RT5665_DIG_DP_MASK                     (0x1 << 6)
+#define RT5665_DIG_DP_SFT                      6
+#define RT5665_DIG_DP_DIS                      (0x0 << 6)
+#define RT5665_DIG_DP_EN                       (0x1 << 6)
+#define RT5665_DP_TH_MASK                      (0x3 << 4)
+#define RT5665_DP_TH_SFT                       4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5665_CP_SYS_MASK                     (0x7 << 12)
+#define RT5665_CP_SYS_SFT                      12
+#define RT5665_CP_FQ1_MASK                     (0x7 << 8)
+#define RT5665_CP_FQ1_SFT                      8
+#define RT5665_CP_FQ2_MASK                     (0x7 << 4)
+#define RT5665_CP_FQ2_SFT                      4
+#define RT5665_CP_FQ3_MASK                     (0x7)
+#define RT5665_CP_FQ3_SFT                      0
+#define RT5665_CP_FQ_1_5_KHZ                   0
+#define RT5665_CP_FQ_3_KHZ                     1
+#define RT5665_CP_FQ_6_KHZ                     2
+#define RT5665_CP_FQ_12_KHZ                    3
+#define RT5665_CP_FQ_24_KHZ                    4
+#define RT5665_CP_FQ_48_KHZ                    5
+#define RT5665_CP_FQ_96_KHZ                    6
+#define RT5665_CP_FQ_192_KHZ                   7
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5665_OSW_L_MASK                      (0x1 << 11)
+#define RT5665_OSW_L_SFT                       11
+#define RT5665_OSW_L_DIS                       (0x0 << 11)
+#define RT5665_OSW_L_EN                                (0x1 << 11)
+#define RT5665_OSW_R_MASK                      (0x1 << 10)
+#define RT5665_OSW_R_SFT                       10
+#define RT5665_OSW_R_DIS                       (0x0 << 10)
+#define RT5665_OSW_R_EN                                (0x1 << 10)
+#define RT5665_PM_HP_MASK                      (0x3 << 8)
+#define RT5665_PM_HP_SFT                       8
+#define RT5665_PM_HP_LV                                (0x0 << 8)
+#define RT5665_PM_HP_MV                                (0x1 << 8)
+#define RT5665_PM_HP_HV                                (0x2 << 8)
+#define RT5665_IB_HP_MASK                      (0x3 << 6)
+#define RT5665_IB_HP_SFT                       6
+#define RT5665_IB_HP_125IL                     (0x0 << 6)
+#define RT5665_IB_HP_25IL                      (0x1 << 6)
+#define RT5665_IB_HP_5IL                       (0x2 << 6)
+#define RT5665_IB_HP_1IL                       (0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5665_PVDD_DET_MASK                   (0x1 << 15)
+#define RT5665_PVDD_DET_SFT                    15
+#define RT5665_PVDD_DET_DIS                    (0x0 << 15)
+#define RT5665_PVDD_DET_EN                     (0x1 << 15)
+#define RT5665_SPK_AG_MASK                     (0x1 << 14)
+#define RT5665_SPK_AG_SFT                      14
+#define RT5665_SPK_AG_DIS                      (0x0 << 14)
+#define RT5665_SPK_AG_EN                       (0x1 << 14)
+
+/* Micbias Control1 (0x93) */
+#define RT5665_MIC1_BS_MASK                    (0x1 << 15)
+#define RT5665_MIC1_BS_SFT                     15
+#define RT5665_MIC1_BS_9AV                     (0x0 << 15)
+#define RT5665_MIC1_BS_75AV                    (0x1 << 15)
+#define RT5665_MIC2_BS_MASK                    (0x1 << 14)
+#define RT5665_MIC2_BS_SFT                     14
+#define RT5665_MIC2_BS_9AV                     (0x0 << 14)
+#define RT5665_MIC2_BS_75AV                    (0x1 << 14)
+#define RT5665_MIC1_CLK_MASK                   (0x1 << 13)
+#define RT5665_MIC1_CLK_SFT                    13
+#define RT5665_MIC1_CLK_DIS                    (0x0 << 13)
+#define RT5665_MIC1_CLK_EN                     (0x1 << 13)
+#define RT5665_MIC2_CLK_MASK                   (0x1 << 12)
+#define RT5665_MIC2_CLK_SFT                    12
+#define RT5665_MIC2_CLK_DIS                    (0x0 << 12)
+#define RT5665_MIC2_CLK_EN                     (0x1 << 12)
+#define RT5665_MIC1_OVCD_MASK                  (0x1 << 11)
+#define RT5665_MIC1_OVCD_SFT                   11
+#define RT5665_MIC1_OVCD_DIS                   (0x0 << 11)
+#define RT5665_MIC1_OVCD_EN                    (0x1 << 11)
+#define RT5665_MIC1_OVTH_MASK                  (0x3 << 9)
+#define RT5665_MIC1_OVTH_SFT                   9
+#define RT5665_MIC1_OVTH_600UA                 (0x0 << 9)
+#define RT5665_MIC1_OVTH_1500UA                        (0x1 << 9)
+#define RT5665_MIC1_OVTH_2000UA                        (0x2 << 9)
+#define RT5665_MIC2_OVCD_MASK                  (0x1 << 8)
+#define RT5665_MIC2_OVCD_SFT                   8
+#define RT5665_MIC2_OVCD_DIS                   (0x0 << 8)
+#define RT5665_MIC2_OVCD_EN                    (0x1 << 8)
+#define RT5665_MIC2_OVTH_MASK                  (0x3 << 6)
+#define RT5665_MIC2_OVTH_SFT                   6
+#define RT5665_MIC2_OVTH_600UA                 (0x0 << 6)
+#define RT5665_MIC2_OVTH_1500UA                        (0x1 << 6)
+#define RT5665_MIC2_OVTH_2000UA                        (0x2 << 6)
+#define RT5665_PWR_MB_MASK                     (0x1 << 5)
+#define RT5665_PWR_MB_SFT                      5
+#define RT5665_PWR_MB_PD                       (0x0 << 5)
+#define RT5665_PWR_MB_PU                       (0x1 << 5)
+
+/* Micbias Control2 (0x94) */
+#define RT5665_PWR_CLK25M_MASK                 (0x1 << 9)
+#define RT5665_PWR_CLK25M_SFT                  9
+#define RT5665_PWR_CLK25M_PD                   (0x0 << 9)
+#define RT5665_PWR_CLK25M_PU                   (0x1 << 9)
+#define RT5665_PWR_CLK1M_MASK                  (0x1 << 8)
+#define RT5665_PWR_CLK1M_SFT                   8
+#define RT5665_PWR_CLK1M_PD                    (0x0 << 8)
+#define RT5665_PWR_CLK1M_PU                    (0x1 << 8)
+
+
+/* EQ Control 1 (0x00b0) */
+#define RT5665_EQ_SRC_DAC                      (0x0 << 15)
+#define RT5665_EQ_SRC_ADC                      (0x1 << 15)
+#define RT5665_EQ_UPD                          (0x1 << 14)
+#define RT5665_EQ_UPD_BIT                      14
+#define RT5665_EQ_CD_MASK                      (0x1 << 13)
+#define RT5665_EQ_CD_SFT                       13
+#define RT5665_EQ_CD_DIS                       (0x0 << 13)
+#define RT5665_EQ_CD_EN                                (0x1 << 13)
+#define RT5665_EQ_DITH_MASK                    (0x3 << 8)
+#define RT5665_EQ_DITH_SFT                     8
+#define RT5665_EQ_DITH_NOR                     (0x0 << 8)
+#define RT5665_EQ_DITH_LSB                     (0x1 << 8)
+#define RT5665_EQ_DITH_LSB_1                   (0x2 << 8)
+#define RT5665_EQ_DITH_LSB_2                   (0x3 << 8)
+
+/* IRQ Control 1 (0x00b7) */
+#define RT5665_JD1_1_EN_MASK                   (0x1 << 15)
+#define RT5665_JD1_1_EN_SFT                    15
+#define RT5665_JD1_1_DIS                       (0x0 << 15)
+#define RT5665_JD1_1_EN                                (0x1 << 15)
+#define RT5665_JD1_2_EN_MASK                   (0x1 << 12)
+#define RT5665_JD1_2_EN_SFT                    12
+#define RT5665_JD1_2_DIS                       (0x0 << 12)
+#define RT5665_JD1_2_EN                                (0x1 << 12)
+
+/* IRQ Control 2 (0x00b8) */
+#define RT5665_IL_IRQ_MASK                     (0x1 << 6)
+#define RT5665_IL_IRQ_DIS                      (0x0 << 6)
+#define RT5665_IL_IRQ_EN                       (0x1 << 6)
+
+/* IRQ Control 5 (0x00ba) */
+#define RT5665_IRQ_JD_EN                       (0x1 << 3)
+#define RT5665_IRQ_JD_EN_SFT                   3
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5665_GP1_PIN_MASK                    (0x1 << 15)
+#define RT5665_GP1_PIN_SFT                     15
+#define RT5665_GP1_PIN_GPIO1                   (0x0 << 15)
+#define RT5665_GP1_PIN_IRQ                     (0x1 << 15)
+#define RT5665_GP2_PIN_MASK                    (0x3 << 13)
+#define RT5665_GP2_PIN_SFT                     13
+#define RT5665_GP2_PIN_GPIO2                   (0x0 << 13)
+#define RT5665_GP2_PIN_BCLK2                   (0x1 << 13)
+#define RT5665_GP2_PIN_PDM_SCL                 (0x2 << 13)
+#define RT5665_GP3_PIN_MASK                    (0x3 << 11)
+#define RT5665_GP3_PIN_SFT                     11
+#define RT5665_GP3_PIN_GPIO3                   (0x0 << 11)
+#define RT5665_GP3_PIN_LRCK2                   (0x1 << 11)
+#define RT5665_GP3_PIN_PDM_SDA                 (0x2 << 11)
+#define RT5665_GP4_PIN_MASK                    (0x3 << 9)
+#define RT5665_GP4_PIN_SFT                     9
+#define RT5665_GP4_PIN_GPIO4                   (0x0 << 9)
+#define RT5665_GP4_PIN_DACDAT2_1               (0x1 << 9)
+#define RT5665_GP4_PIN_DMIC1_SDA               (0x2 << 9)
+#define RT5665_GP5_PIN_MASK                    (0x3 << 7)
+#define RT5665_GP5_PIN_SFT                     7
+#define RT5665_GP5_PIN_GPIO5                   (0x0 << 7)
+#define RT5665_GP5_PIN_ADCDAT2_1               (0x1 << 7)
+#define RT5665_GP5_PIN_DMIC2_SDA               (0x2 << 7)
+#define RT5665_GP6_PIN_MASK                    (0x3 << 5)
+#define RT5665_GP6_PIN_SFT                     5
+#define RT5665_GP6_PIN_GPIO6                   (0x0 << 5)
+#define RT5665_GP6_PIN_BCLK3                   (0x0 << 5)
+#define RT5665_GP6_PIN_PDM_SCL                 (0x1 << 5)
+#define RT5665_GP7_PIN_MASK                    (0x3 << 3)
+#define RT5665_GP7_PIN_SFT                     3
+#define RT5665_GP7_PIN_GPIO7                   (0x0 << 3)
+#define RT5665_GP7_PIN_LRCK3                   (0x1 << 3)
+#define RT5665_GP7_PIN_PDM_SDA                 (0x2 << 3)
+#define RT5665_GP8_PIN_MASK                    (0x3 << 1)
+#define RT5665_GP8_PIN_SFT                     1
+#define RT5665_GP8_PIN_GPIO8                   (0x0 << 1)
+#define RT5665_GP8_PIN_DACDAT3                 (0x1 << 1)
+#define RT5665_GP8_PIN_DMIC2_SCL               (0x2 << 1)
+#define RT5665_GP8_PIN_DACDAT2_2               (0x3 << 1)
+
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5665_GP9_PIN_MASK                    (0x3 << 14)
+#define RT5665_GP9_PIN_SFT                     14
+#define RT5665_GP9_PIN_GPIO9                   (0x0 << 14)
+#define RT5665_GP9_PIN_ADCDAT3                 (0x1 << 14)
+#define RT5665_GP9_PIN_DMIC1_SCL               (0x2 << 14)
+#define RT5665_GP9_PIN_ADCDAT2_2               (0x3 << 14)
+#define RT5665_GP10_PIN_MASK                   (0x3 << 12)
+#define RT5665_GP10_PIN_SFT                    12
+#define RT5665_GP10_PIN_GPIO10                 (0x0 << 12)
+#define RT5665_GP10_PIN_ADCDAT1_2              (0x1 << 12)
+#define RT5665_GP10_PIN_LPD                    (0x2 << 12)
+#define RT5665_GP1_PF_MASK                     (0x1 << 11)
+#define RT5665_GP1_PF_IN                       (0x0 << 11)
+#define RT5665_GP1_PF_OUT                      (0x1 << 11)
+#define RT5665_GP1_OUT_MASK                    (0x1 << 10)
+#define RT5665_GP1_OUT_H                       (0x0 << 10)
+#define RT5665_GP1_OUT_L                       (0x1 << 10)
+#define RT5665_GP2_PF_MASK                     (0x1 << 9)
+#define RT5665_GP2_PF_IN                       (0x0 << 9)
+#define RT5665_GP2_PF_OUT                      (0x1 << 9)
+#define RT5665_GP2_OUT_MASK                    (0x1 << 8)
+#define RT5665_GP2_OUT_H                       (0x0 << 8)
+#define RT5665_GP2_OUT_L                       (0x1 << 8)
+#define RT5665_GP3_PF_MASK                     (0x1 << 7)
+#define RT5665_GP3_PF_IN                       (0x0 << 7)
+#define RT5665_GP3_PF_OUT                      (0x1 << 7)
+#define RT5665_GP3_OUT_MASK                    (0x1 << 6)
+#define RT5665_GP3_OUT_H                       (0x0 << 6)
+#define RT5665_GP3_OUT_L                       (0x1 << 6)
+#define RT5665_GP4_PF_MASK                     (0x1 << 5)
+#define RT5665_GP4_PF_IN                       (0x0 << 5)
+#define RT5665_GP4_PF_OUT                      (0x1 << 5)
+#define RT5665_GP4_OUT_MASK                    (0x1 << 4)
+#define RT5665_GP4_OUT_H                       (0x0 << 4)
+#define RT5665_GP4_OUT_L                       (0x1 << 4)
+#define RT5665_GP5_PF_MASK                     (0x1 << 3)
+#define RT5665_GP5_PF_IN                       (0x0 << 3)
+#define RT5665_GP5_PF_OUT                      (0x1 << 3)
+#define RT5665_GP5_OUT_MASK                    (0x1 << 2)
+#define RT5665_GP5_OUT_H                       (0x0 << 2)
+#define RT5665_GP5_OUT_L                       (0x1 << 2)
+#define RT5665_GP6_PF_MASK                     (0x1 << 1)
+#define RT5665_GP6_PF_IN                       (0x0 << 1)
+#define RT5665_GP6_PF_OUT                      (0x1 << 1)
+#define RT5665_GP6_OUT_MASK                    (0x1)
+#define RT5665_GP6_OUT_H                       (0x0)
+#define RT5665_GP6_OUT_L                       (0x1)
+
+
+/* GPIO Control 3 (0x00c2) */
+#define RT5665_GP7_PF_MASK                     (0x1 << 15)
+#define RT5665_GP7_PF_IN                       (0x0 << 15)
+#define RT5665_GP7_PF_OUT                      (0x1 << 15)
+#define RT5665_GP7_OUT_MASK                    (0x1 << 14)
+#define RT5665_GP7_OUT_H                       (0x0 << 14)
+#define RT5665_GP7_OUT_L                       (0x1 << 14)
+#define RT5665_GP8_PF_MASK                     (0x1 << 13)
+#define RT5665_GP8_PF_IN                       (0x0 << 13)
+#define RT5665_GP8_PF_OUT                      (0x1 << 13)
+#define RT5665_GP8_OUT_MASK                    (0x1 << 12)
+#define RT5665_GP8_OUT_H                       (0x0 << 12)
+#define RT5665_GP8_OUT_L                       (0x1 << 12)
+#define RT5665_GP9_PF_MASK                     (0x1 << 11)
+#define RT5665_GP9_PF_IN                       (0x0 << 11)
+#define RT5665_GP9_PF_OUT                      (0x1 << 11)
+#define RT5665_GP9_OUT_MASK                    (0x1 << 10)
+#define RT5665_GP9_OUT_H                       (0x0 << 10)
+#define RT5665_GP9_OUT_L                       (0x1 << 10)
+#define RT5665_GP10_PF_MASK                    (0x1 << 9)
+#define RT5665_GP10_PF_IN                      (0x0 << 9)
+#define RT5665_GP10_PF_OUT                     (0x1 << 9)
+#define RT5665_GP10_OUT_MASK                   (0x1 << 8)
+#define RT5665_GP10_OUT_H                      (0x0 << 8)
+#define RT5665_GP10_OUT_L                      (0x1 << 8)
+#define RT5665_GP11_PF_MASK                    (0x1 << 7)
+#define RT5665_GP11_PF_IN                      (0x0 << 7)
+#define RT5665_GP11_PF_OUT                     (0x1 << 7)
+#define RT5665_GP11_OUT_MASK                   (0x1 << 6)
+#define RT5665_GP11_OUT_H                      (0x0 << 6)
+#define RT5665_GP11_OUT_L                      (0x1 << 6)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5665_SV_MASK                         (0x1 << 15)
+#define RT5665_SV_SFT                          15
+#define RT5665_SV_DIS                          (0x0 << 15)
+#define RT5665_SV_EN                           (0x1 << 15)
+#define RT5665_OUT_SV_MASK                     (0x1 << 13)
+#define RT5665_OUT_SV_SFT                      13
+#define RT5665_OUT_SV_DIS                      (0x0 << 13)
+#define RT5665_OUT_SV_EN                       (0x1 << 13)
+#define RT5665_HP_SV_MASK                      (0x1 << 12)
+#define RT5665_HP_SV_SFT                       12
+#define RT5665_HP_SV_DIS                       (0x0 << 12)
+#define RT5665_HP_SV_EN                                (0x1 << 12)
+#define RT5665_ZCD_DIG_MASK                    (0x1 << 11)
+#define RT5665_ZCD_DIG_SFT                     11
+#define RT5665_ZCD_DIG_DIS                     (0x0 << 11)
+#define RT5665_ZCD_DIG_EN                      (0x1 << 11)
+#define RT5665_ZCD_MASK                                (0x1 << 10)
+#define RT5665_ZCD_SFT                         10
+#define RT5665_ZCD_PD                          (0x0 << 10)
+#define RT5665_ZCD_PU                          (0x1 << 10)
+#define RT5665_SV_DLY_MASK                     (0xf)
+#define RT5665_SV_DLY_SFT                      0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5665_ZCD_HP_MASK                     (0x1 << 15)
+#define RT5665_ZCD_HP_SFT                      15
+#define RT5665_ZCD_HP_DIS                      (0x0 << 15)
+#define RT5665_ZCD_HP_EN                       (0x1 << 15)
+
+/* 4 Button Inline Command Control 2 (0x00e0) */
+#define RT5665_4BTN_IL_MASK                    (0x1 << 15)
+#define RT5665_4BTN_IL_EN                      (0x1 << 15)
+#define RT5665_4BTN_IL_DIS                     (0x0 << 15)
+#define RT5665_4BTN_IL_RST_MASK                        (0x1 << 14)
+#define RT5665_4BTN_IL_NOR                     (0x1 << 14)
+#define RT5665_4BTN_IL_RST                     (0x0 << 14)
+
+/* Analog JD Control 1 (0x00f0) */
+#define RT5665_JD1_MODE_MASK                   (0x3 << 0)
+#define RT5665_JD1_MODE_0                      (0x0 << 0)
+#define RT5665_JD1_MODE_1                      (0x1 << 0)
+#define RT5665_JD1_MODE_2                      (0x2 << 0)
+
+/* Jack Detect Control 3 (0x00f8) */
+#define RT5665_JD_TRI_HPO_SEL_MASK             (0x7)
+#define RT5665_JD_TRI_HPO_SEL_SFT              (0)
+#define RT5665_JD_HPO_GPIO_JD1                 (0x0)
+#define RT5665_JD_HPO_JD1_1                    (0x1)
+#define RT5665_JD_HPO_JD1_2                    (0x2)
+#define RT5665_JD_HPO_JD2                      (0x3)
+#define RT5665_JD_HPO_GPIO_JD2                 (0x4)
+#define RT5665_JD_HPO_JD3                      (0x5)
+#define RT5665_JD_HPO_JD_D                     (0x6)
+
+/* Digital Misc Control (0x00fa) */
+#define RT5665_AM_MASK                         (0x1 << 7)
+#define RT5665_AM_EN                           (0x1 << 7)
+#define RT5665_AM_DIS                          (0x1 << 7)
+#define RT5665_DIG_GATE_CTRL                   0x1
+#define RT5665_DIG_GATE_CTRL_SFT               (0)
+
+/* Chopper and Clock control for ADC (0x011c)*/
+#define RT5665_M_RF_DIG_MASK                   (0x1 << 12)
+#define RT5665_M_RF_DIG_SFT                    12
+#define RT5665_M_RI_DIG                                (0x1 << 11)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5665_CKXEN_DAC1_MASK                 (0x1 << 13)
+#define RT5665_CKXEN_DAC1_SFT                  13
+#define RT5665_CKGEN_DAC1_MASK                 (0x1 << 12)
+#define RT5665_CKGEN_DAC1_SFT                  12
+#define RT5665_CKXEN_DAC2_MASK                 (0x1 << 5)
+#define RT5665_CKXEN_DAC2_SFT                  5
+#define RT5665_CKGEN_DAC2_MASK                 (0x1 << 4)
+#define RT5665_CKGEN_DAC2_SFT                  4
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5665_CKXEN_ADC1_MASK                 (0x1 << 13)
+#define RT5665_CKXEN_ADC1_SFT                  13
+#define RT5665_CKGEN_ADC1_MASK                 (0x1 << 12)
+#define RT5665_CKGEN_ADC1_SFT                  12
+#define RT5665_CKXEN_ADC2_MASK                 (0x1 << 5)
+#define RT5665_CKXEN_ADC2_SFT                  5
+#define RT5665_CKGEN_ADC2_MASK                 (0x1 << 4)
+#define RT5665_CKGEN_ADC2_SFT                  4
+
+/* Volume test (0x013f)*/
+#define RT5665_SEL_CLK_VOL_MASK                        (0x1 << 15)
+#define RT5665_SEL_CLK_VOL_EN                  (0x1 << 15)
+#define RT5665_SEL_CLK_VOL_DIS                 (0x0 << 15)
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5665_AD2DA_LB_MASK                   (0x1 << 9)
+#define RT5665_AD2DA_LB_SFT                    9
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5665_NG2_EN_MASK                     (0x1 << 15)
+#define RT5665_NG2_EN                          (0x1 << 15)
+#define RT5665_NG2_DIS                         (0x0 << 15)
+
+/* Stereo1 DAC Silence Detection Control (0x0190) */
+#define RT5665_DEB_STO_DAC_MASK                        (0x7 << 4)
+#define RT5665_DEB_80_MS                       (0x0 << 4)
+
+/* SAR ADC Inline Command Control 1 (0x0210) */
+#define RT5665_SAR_BUTT_DET_MASK               (0x1 << 15)
+#define RT5665_SAR_BUTT_DET_EN                 (0x1 << 15)
+#define RT5665_SAR_BUTT_DET_DIS                        (0x0 << 15)
+#define RT5665_SAR_BUTDET_MODE_MASK            (0x1 << 14)
+#define RT5665_SAR_BUTDET_POW_SAV              (0x1 << 14)
+#define RT5665_SAR_BUTDET_POW_NORM             (0x0 << 14)
+#define RT5665_SAR_BUTDET_RST_MASK             (0x1 << 13)
+#define RT5665_SAR_BUTDET_RST_NORMAL           (0x1 << 13)
+#define RT5665_SAR_BUTDET_RST                  (0x0 << 13)
+#define RT5665_SAR_POW_MASK                    (0x1 << 12)
+#define RT5665_SAR_POW_EN                      (0x1 << 12)
+#define RT5665_SAR_POW_DIS                     (0x0 << 12)
+#define RT5665_SAR_RST_MASK                    (0x1 << 11)
+#define RT5665_SAR_RST_NORMAL                  (0x1 << 11)
+#define RT5665_SAR_RST                         (0x0 << 11)
+#define RT5665_SAR_BYPASS_MASK                 (0x1 << 10)
+#define RT5665_SAR_BYPASS_EN                   (0x1 << 10)
+#define RT5665_SAR_BYPASS_DIS                  (0x0 << 10)
+#define RT5665_SAR_SEL_MB1_MASK                        (0x1 << 9)
+#define RT5665_SAR_SEL_MB1_SEL                 (0x1 << 9)
+#define RT5665_SAR_SEL_MB1_NOSEL               (0x0 << 9)
+#define RT5665_SAR_SEL_MB2_MASK                        (0x1 << 8)
+#define RT5665_SAR_SEL_MB2_SEL                 (0x1 << 8)
+#define RT5665_SAR_SEL_MB2_NOSEL               (0x0 << 8)
+#define RT5665_SAR_SEL_MODE_MASK               (0x1 << 7)
+#define RT5665_SAR_SEL_MODE_CMP                        (0x1 << 7)
+#define RT5665_SAR_SEL_MODE_ADC                        (0x0 << 7)
+#define RT5665_SAR_SEL_MB1_MB2_MASK            (0x1 << 5)
+#define RT5665_SAR_SEL_MB1_MB2_AUTO            (0x1 << 5)
+#define RT5665_SAR_SEL_MB1_MB2_MANU            (0x0 << 5)
+#define RT5665_SAR_SEL_SIGNAL_MASK             (0x1 << 4)
+#define RT5665_SAR_SEL_SIGNAL_AUTO             (0x1 << 4)
+#define RT5665_SAR_SEL_SIGNAL_MANU             (0x0 << 4)
+
+/* System Clock Source */
+enum {
+       RT5665_SCLK_S_MCLK,
+       RT5665_SCLK_S_PLL1,
+       RT5665_SCLK_S_RCCLK,
+};
+
+/* PLL1 Source */
+enum {
+       RT5665_PLL1_S_MCLK,
+       RT5665_PLL1_S_BCLK1,
+       RT5665_PLL1_S_BCLK2,
+       RT5665_PLL1_S_BCLK3,
+       RT5665_PLL1_S_BCLK4,
+};
+
+enum {
+       RT5665_AIF1_1,
+       RT5665_AIF1_2,
+       RT5665_AIF2_1,
+       RT5665_AIF2_2,
+       RT5665_AIF3,
+       RT5665_AIFS
+};
+
+enum {
+       CODEC_5665,
+       CODEC_5666,
+       CODEC_5668,
+};
+
+/* filter mask */
+enum {
+       RT5665_DA_STEREO1_FILTER = 0x1,
+       RT5665_DA_STEREO2_FILTER = (0x1 << 1),
+       RT5665_DA_MONO_L_FILTER = (0x1 << 2),
+       RT5665_DA_MONO_R_FILTER = (0x1 << 3),
+       RT5665_AD_STEREO1_FILTER = (0x1 << 4),
+       RT5665_AD_STEREO2_FILTER = (0x1 << 5),
+       RT5665_AD_MONO_L_FILTER = (0x1 << 6),
+       RT5665_AD_MONO_R_FILTER = (0x1 << 7),
+};
+
+enum {
+       RT5665_CLK_SEL_SYS,
+       RT5665_CLK_SEL_I2S1_ASRC,
+       RT5665_CLK_SEL_I2S2_ASRC,
+       RT5665_CLK_SEL_I2S3_ASRC,
+       RT5665_CLK_SEL_SYS2,
+       RT5665_CLK_SEL_SYS3,
+       RT5665_CLK_SEL_SYS4,
+};
+
+int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec,
+               unsigned int filter_mask, unsigned int clk_src);
+int rt5665_set_jack_detect(struct snd_soc_codec *codec,
+       struct snd_soc_jack *hs_jack);
+
+#endif /* __RT5665_H__ */
index 7b31ee9b82bc87beb493427049fc82d75e1127e8..d6e00c77edcd7360b8df3d9942e5c4213ba530b6 100644 (file)
@@ -424,7 +424,7 @@ static const struct snd_soc_dai_ops stih407_dac_ops = {
 static const struct regmap_config stih407_sas_regmap = {
        .reg_bits = 32,
        .val_bits = 32,
-
+       .fast_io = true,
        .max_register = STIH407_AUDIO_DAC_CTRL,
        .reg_defaults = stih407_sas_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
index df5e5cb33baaba035b1d9db577cbf772855ac3e9..810369f687d7166755a6b639fbfb97ed3b9672e7 100644 (file)
@@ -341,20 +341,9 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec,
                                        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;
@@ -401,16 +390,6 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
                   TAS571X_SOFT_MUTE_REG,
                   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
                   1, 1),
-
-       SOC_DOUBLE_R_RANGE("CH1 Mixer Volume",
-                          TAS5717_CH1_LEFT_CH_MIX_REG,
-                          TAS5717_CH1_RIGHT_CH_MIX_REG,
-                          16, 0, 0x80, 0),
-
-       SOC_DOUBLE_R_RANGE("CH2 Mixer Volume",
-                          TAS5717_CH2_LEFT_CH_MIX_REG,
-                          TAS5717_CH2_RIGHT_CH_MIX_REG,
-                          16, 0, 0x80, 0),
 };
 
 static const struct regmap_range tas571x_readonly_regs_range[] = {
@@ -488,6 +467,16 @@ static const struct snd_kcontrol_new tas5717_controls[] = {
                   TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
                   1, 1),
 
+       SOC_DOUBLE_R_RANGE("CH1 Mixer Volume",
+                          TAS5717_CH1_LEFT_CH_MIX_REG,
+                          TAS5717_CH1_RIGHT_CH_MIX_REG,
+                          16, 0, 0x80, 0),
+
+       SOC_DOUBLE_R_RANGE("CH2 Mixer Volume",
+                          TAS5717_CH2_LEFT_CH_MIX_REG,
+                          TAS5717_CH2_RIGHT_CH_MIX_REG,
+                          16, 0, 0x80, 0),
+
        /*
         * The biquads are named according to the register names.
         * Please note that TI's TAS57xx Graphical Development Environment
@@ -747,13 +736,14 @@ static int tas571x_i2c_probe(struct i2c_client *client,
                /* pulse the active low reset line for ~100us */
                usleep_range(100, 200);
                gpiod_set_value(priv->reset_gpio, 0);
-               usleep_range(12000, 20000);
+               usleep_range(13500, 20000);
        }
 
        ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0);
        if (ret)
                return ret;
 
+       usleep_range(50000, 60000);
 
        memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
        priv->codec_driver.component_driver.controls = priv->chip->controls;
@@ -770,9 +760,6 @@ static int tas571x_i2c_probe(struct i2c_client *client,
                        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);
 }
index 5a8d96ec058c5e5464a251d86edcc2920c5e14c7..8877b74b0510fedefe81adc6637c9d72cf9c722f 100644 (file)
@@ -157,7 +157,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
        unsigned short val;
-       struct snd_soc_dapm_update update;
+       struct snd_soc_dapm_update update = { 0 };
        int connect, change;
 
        val = (ucontrol->value.integer.value[0] & mask);
index 93876c6d48ee9a850516771339fad3be22ce980b..e7ab37d0dd325c0614e18ce6b2c671acee1c2915 100644 (file)
@@ -607,6 +607,9 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
                break;
        case SND_SOC_DAPM_PRE_PMD:
                break;
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               return arizona_clk_ev(w, kcontrol, event);
        default:
                return 0;
        }
@@ -1077,9 +1080,11 @@ 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 | SND_SOC_DAPM_PRE_PMD),
+                   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
-                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
                    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
@@ -1903,7 +1908,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
 static int wm5102_open(struct snd_compr_stream *stream)
 {
        struct snd_soc_pcm_runtime *rtd = stream->private_data;
-       struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+       struct wm5102_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
 
        return wm_adsp_compr_open(&priv->core.adsp[0], stream);
 }
@@ -1926,18 +1931,10 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
 static int wm5102_codec_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->core.arizona;
        int ret;
 
-       ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
-                                 "ADSP2 Compressed IRQ", wm5102_adsp2_irq,
-                                 priv);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
-               return ret;
-       }
-
        ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
        if (ret)
                return ret;
@@ -1949,8 +1946,9 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
 
        arizona_init_spk(codec);
        arizona_init_gpio(codec);
+       arizona_init_notifiers(codec);
 
-       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+       snd_soc_component_disable_pin(component, "HAPTICS");
 
        priv->core.arizona->dapm = dapm;
 
@@ -1965,16 +1963,11 @@ err_adsp2_codec_probe:
 static int wm5102_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->core.arizona;
 
        wm_adsp2_codec_remove(&priv->core.adsp[0], codec);
 
        priv->core.arizona->dapm = NULL;
 
-       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
-
-       arizona_free_spk(codec);
-
        return 0;
 }
 
@@ -2092,25 +2085,47 @@ static int wm5102_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
 
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+                                 "ADSP2 Compressed IRQ", wm5102_adsp2_irq,
+                                 wm5102);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
+               return ret;
+       }
+
+       ret = arizona_init_spk_irqs(arizona);
+       if (ret < 0)
+               goto err_dsp_irq;
+
        ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
-               return ret;
+               goto err_spk_irqs;
        }
 
        ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
                                      wm5102_dai, ARRAY_SIZE(wm5102_dai));
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
-               snd_soc_unregister_platform(&pdev->dev);
+               goto err_platform;
        }
 
+       return ret;
+
+err_platform:
+       snd_soc_unregister_platform(&pdev->dev);
+err_spk_irqs:
+       arizona_free_spk_irqs(arizona);
+err_dsp_irq:
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
+
        return ret;
 }
 
 static int wm5102_remove(struct platform_device *pdev)
 {
        struct wm5102_priv *wm5102 = platform_get_drvdata(pdev);
+       struct arizona *arizona = wm5102->core.arizona;
 
        snd_soc_unregister_platform(&pdev->dev);
        snd_soc_unregister_codec(&pdev->dev);
@@ -2118,6 +2133,10 @@ static int wm5102_remove(struct platform_device *pdev)
 
        wm_adsp2_remove(&wm5102->core.adsp[0]);
 
+       arizona_free_spk_irqs(arizona);
+
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
+
        return 0;
 }
 
index 06bae3b23fced6fa4efa949e8fdb2af7bdb20499..585fc706c1b0e7b112887be058a755b800ed1ca9 100644 (file)
@@ -183,7 +183,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
                                regmap_write_async(regmap, patch[i].reg,
                                                   patch[i].def);
                break;
-
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               return arizona_clk_ev(w, kcontrol, event);
        default:
                break;
        }
@@ -1073,9 +1075,11 @@ static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
 
 static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
-                   0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
+                   0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU |
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
-                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
                    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
@@ -2220,7 +2224,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
 static int wm5110_open(struct snd_compr_stream *stream)
 {
        struct snd_soc_pcm_runtime *rtd = stream->private_data;
-       struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+       struct wm5110_priv *priv = snd_soc_platform_get_drvdata(rtd->platform);
        struct arizona *arizona = priv->core.arizona;
        int n_adsp;
 
@@ -2269,8 +2273,8 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
 static int wm5110_codec_probe(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->core.arizona;
        int i, ret;
 
        priv->core.arizona->dapm = dapm;
@@ -2280,14 +2284,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
        arizona_init_mono(codec);
        arizona_init_notifiers(codec);
 
-       ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
-                                 "ADSP2 Compressed IRQ", wm5110_adsp2_irq,
-                                 priv);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
-               return ret;
-       }
-
        for (i = 0; i < WM5110_NUM_ADSP; ++i) {
                ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
                if (ret)
@@ -2300,7 +2296,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
        if (ret)
                goto err_adsp2_codec_probe;
 
-       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+       snd_soc_component_disable_pin(component, "HAPTICS");
 
        return 0;
 
@@ -2308,15 +2304,12 @@ err_adsp2_codec_probe:
        for (--i; i >= 0; --i)
                wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
 
-       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
-
        return ret;
 }
 
 static int wm5110_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
-       struct arizona *arizona = priv->core.arizona;
        int i;
 
        for (i = 0; i < WM5110_NUM_ADSP; ++i)
@@ -2324,10 +2317,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
 
        priv->core.arizona->dapm = NULL;
 
-       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
-
-       arizona_free_spk(codec);
-
        return 0;
 }
 
@@ -2449,25 +2438,47 @@ static int wm5110_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
 
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+                                 "ADSP2 Compressed IRQ", wm5110_adsp2_irq,
+                                 wm5110);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret);
+               return ret;
+       }
+
+       ret = arizona_init_spk_irqs(arizona);
+       if (ret < 0)
+               goto err_dsp_irq;
+
        ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
-               return ret;
+               goto err_spk_irqs;
        }
 
        ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
                                      wm5110_dai, ARRAY_SIZE(wm5110_dai));
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
-               snd_soc_unregister_platform(&pdev->dev);
+               goto err_platform;
        }
 
+       return ret;
+
+err_platform:
+       snd_soc_unregister_platform(&pdev->dev);
+err_spk_irqs:
+       arizona_free_spk_irqs(arizona);
+err_dsp_irq:
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
+
        return ret;
 }
 
 static int wm5110_remove(struct platform_device *pdev)
 {
        struct wm5110_priv *wm5110 = platform_get_drvdata(pdev);
+       struct arizona *arizona = wm5110->core.arizona;
        int i;
 
        snd_soc_unregister_platform(&pdev->dev);
@@ -2477,6 +2488,10 @@ static int wm5110_remove(struct platform_device *pdev)
        for (i = 0; i < WM5110_NUM_ADSP; i++)
                wm_adsp2_remove(&wm5110->core.adsp[i]);
 
+       arizona_free_spk_irqs(arizona);
+
+       arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
+
        return 0;
 }
 
index 2f2821b3382f055a9560413240797e4c56579c61..ee0c8639c7435c823af8fcbc0161dcdc1342c35c 100644 (file)
@@ -108,6 +108,9 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
                break;
        case SND_SOC_DAPM_PRE_PMD:
                break;
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               return arizona_clk_ev(w, kcontrol, event);
        default:
                return 0;
        }
@@ -408,9 +411,11 @@ 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 | SND_SOC_DAPM_PRE_PMD),
+                   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
-                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
                    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
@@ -1055,11 +1060,13 @@ 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 snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
 
        arizona_init_spk(codec);
+       arizona_init_notifiers(codec);
 
-       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+       snd_soc_component_disable_pin(component, "HAPTICS");
 
        priv->core.arizona->dapm = dapm;
 
@@ -1072,8 +1079,6 @@ static int wm8997_codec_remove(struct snd_soc_codec *codec)
 
        priv->core.arizona->dapm = NULL;
 
-       arizona_free_spk(codec);
-
        return 0;
 }
 
@@ -1119,7 +1124,7 @@ static int wm8997_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
        struct wm8997_priv *wm8997;
-       int i;
+       int i, ret;
 
        wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv),
                              GFP_KERNEL);
@@ -1159,15 +1164,33 @@ static int wm8997_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
 
-       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
-                                     wm8997_dai, ARRAY_SIZE(wm8997_dai));
+       ret = arizona_init_spk_irqs(arizona);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
+                                    wm8997_dai, ARRAY_SIZE(wm8997_dai));
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+               goto err_spk_irqs;
+       }
+
+err_spk_irqs:
+       arizona_free_spk_irqs(arizona);
+
+       return ret;
 }
 
 static int wm8997_remove(struct platform_device *pdev)
 {
+       struct wm8997_priv *wm8997 = platform_get_drvdata(pdev);
+       struct arizona *arizona = wm8997->core.arizona;
+
        snd_soc_unregister_codec(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
+       arizona_free_spk_irqs(arizona);
+
        return 0;
 }
 
index bcc2e1060a6c3ce1e48fce7ea2780249830e6525..3694f5958d869da5bc6b676bbce0e78acc769f46 100644 (file)
@@ -541,9 +541,11 @@ static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = {
 
 static const struct snd_soc_dapm_widget wm8998_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1,
-                   ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0),
+                   ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
-                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
                    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
@@ -1318,13 +1320,15 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec)
 {
        struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
 
        priv->core.arizona->dapm = dapm;
 
        arizona_init_spk(codec);
        arizona_init_gpio(codec);
+       arizona_init_notifiers(codec);
 
-       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
+       snd_soc_component_disable_pin(component, "HAPTICS");
 
        return 0;
 }
@@ -1335,8 +1339,6 @@ static int wm8998_codec_remove(struct snd_soc_codec *codec)
 
        priv->core.arizona->dapm = NULL;
 
-       arizona_free_spk(codec);
-
        return 0;
 }
 
@@ -1385,7 +1387,7 @@ static int wm8998_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
        struct wm8998_priv *wm8998;
-       int i;
+       int i, ret;
 
        wm8998 = devm_kzalloc(&pdev->dev, sizeof(struct wm8998_priv),
                              GFP_KERNEL);
@@ -1417,15 +1419,35 @@ static int wm8998_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
 
-       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998,
-                                     wm8998_dai, ARRAY_SIZE(wm8998_dai));
+       ret = arizona_init_spk_irqs(arizona);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998,
+                                    wm8998_dai, ARRAY_SIZE(wm8998_dai));
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+               goto err_spk_irqs;
+       }
+
+       return ret;
+
+err_spk_irqs:
+       arizona_free_spk_irqs(arizona);
+
+       return ret;
 }
 
 static int wm8998_remove(struct platform_device *pdev)
 {
+       struct wm8998_priv *wm8998 = platform_get_drvdata(pdev);
+       struct arizona *arizona = wm8998->core.arizona;
+
        snd_soc_unregister_codec(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
+       arizona_free_spk_irqs(arizona);
+
        return 0;
 }
 
index 557709eac698fb60c6a66d5af9a88bf744e8256c..85f7c5bb8b825fbba0f14d6ed6f8753b454daaa7 100644 (file)
@@ -187,7 +187,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
-       struct snd_soc_dapm_update update;
+       struct snd_soc_dapm_update update = { 0 };
        bool change;
 
        mixer = mc->shift >> 8;
index e4301ddb1b84e434ce3bbfa5997f20658af30dbd..7e4822185febeac4ae7d2d601f3a76c7659ff924 100644 (file)
@@ -231,7 +231,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mixer, mask, shift, old;
-       struct snd_soc_dapm_update update;
+       struct snd_soc_dapm_update update = { 0 };
        bool change;
 
        mixer = mc->shift >> 8;
index b943dde8dbe594c382ac588f71d1dc90890421b5..593b7d1aed4695bbf6e538fa924bc6263901041f 100644 (file)
 
 #define ADSP_MAX_STD_CTRL_SIZE               512
 
+#define WM_ADSP_ACKED_CTL_TIMEOUT_MS         100
+#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS       10
+#define WM_ADSP_ACKED_CTL_MIN_VALUE          0
+#define WM_ADSP_ACKED_CTL_MAX_VALUE          0xFFFFFF
+
+/*
+ * Event control messages
+ */
+#define WM_ADSP_FW_EVENT_SHUTDOWN            0x000001
+
 struct wm_adsp_buf {
        struct list_head list;
        void *buf;
@@ -177,7 +187,7 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
 
        buf->buf = vmalloc(len);
        if (!buf->buf) {
-               vfree(buf);
+               kfree(buf);
                return NULL;
        }
        memcpy(buf->buf, src, len);
@@ -441,11 +451,29 @@ struct wm_coeff_ctl {
        unsigned int offset;
        size_t len;
        unsigned int set:1;
-       struct snd_kcontrol *kcontrol;
        struct soc_bytes_ext bytes_ext;
        unsigned int flags;
+       unsigned int type;
 };
 
+static const char *wm_adsp_mem_region_name(unsigned int type)
+{
+       switch (type) {
+       case WMFW_ADSP1_PM:
+               return "PM";
+       case WMFW_ADSP1_DM:
+               return "DM";
+       case WMFW_ADSP2_XM:
+               return "XM";
+       case WMFW_ADSP2_YM:
+               return "YM";
+       case WMFW_ADSP1_ZM:
+               return "ZM";
+       default:
+               return NULL;
+       }
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s)
 {
@@ -727,6 +755,24 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
        return container_of(ext, struct wm_coeff_ctl, bytes_ext);
 }
 
+static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg)
+{
+       const struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
+       struct wm_adsp *dsp = ctl->dsp;
+       const struct wm_adsp_region *mem;
+
+       mem = wm_adsp_find_region(dsp, alg_region->type);
+       if (!mem) {
+               adsp_err(dsp, "No base for region %x\n",
+                        alg_region->type);
+               return -EINVAL;
+       }
+
+       *reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset);
+
+       return 0;
+}
+
 static int wm_coeff_info(struct snd_kcontrol *kctl,
                         struct snd_ctl_elem_info *uinfo)
 {
@@ -734,30 +780,94 @@ static int wm_coeff_info(struct snd_kcontrol *kctl,
                (struct soc_bytes_ext *)kctl->private_value;
        struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
 
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-       uinfo->count = ctl->len;
+       switch (ctl->type) {
+       case WMFW_CTL_TYPE_ACKED:
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE;
+               uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE;
+               uinfo->value.integer.step = 1;
+               uinfo->count = 1;
+               break;
+       default:
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+               uinfo->count = ctl->len;
+               break;
+       }
+
        return 0;
 }
 
+static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
+                                       unsigned int event_id)
+{
+       struct wm_adsp *dsp = ctl->dsp;
+       u32 val = cpu_to_be32(event_id);
+       unsigned int reg;
+       int i, ret;
+
+       ret = wm_coeff_base_reg(ctl, &reg);
+       if (ret)
+               return ret;
+
+       adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n",
+                event_id, ctl->alg_region.alg,
+                wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset);
+
+       ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val));
+       if (ret) {
+               adsp_err(dsp, "Failed to write %x: %d\n", reg, ret);
+               return ret;
+       }
+
+       /*
+        * Poll for ack, we initially poll at ~1ms intervals for firmwares
+        * that respond quickly, then go to ~10ms polls. A firmware is unlikely
+        * to ack instantly so we do the first 1ms delay before reading the
+        * control to avoid a pointless bus transaction
+        */
+       for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) {
+               switch (i) {
+               case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1:
+                       usleep_range(1000, 2000);
+                       i++;
+                       break;
+               default:
+                       usleep_range(10000, 20000);
+                       i += 10;
+                       break;
+               }
+
+               ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+               if (ret) {
+                       adsp_err(dsp, "Failed to read %x: %d\n", reg, ret);
+                       return ret;
+               }
+
+               if (val == 0) {
+                       adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i);
+                       return 0;
+               }
+       }
+
+       adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n",
+                 reg, ctl->alg_region.alg,
+                 wm_adsp_mem_region_name(ctl->alg_region.type),
+                 ctl->offset);
+
+       return -ETIMEDOUT;
+}
+
 static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
                                  const void *buf, size_t len)
 {
-       struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
-       const struct wm_adsp_region *mem;
        struct wm_adsp *dsp = ctl->dsp;
        void *scratch;
        int ret;
        unsigned int reg;
 
-       mem = wm_adsp_find_region(dsp, alg_region->type);
-       if (!mem) {
-               adsp_err(dsp, "No base for region %x\n",
-                        alg_region->type);
-               return -EINVAL;
-       }
-
-       reg = ctl->alg_region.base + ctl->offset;
-       reg = wm_adsp_region_to_reg(mem, reg);
+       ret = wm_coeff_base_reg(ctl, &reg);
+       if (ret)
+               return ret;
 
        scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
        if (!scratch)
@@ -823,25 +933,41 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
        return ret;
 }
 
+static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_bytes_ext *bytes_ext =
+               (struct soc_bytes_ext *)kctl->private_value;
+       struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
+       unsigned int val = ucontrol->value.integer.value[0];
+       int ret;
+
+       if (val == 0)
+               return 0;       /* 0 means no event */
+
+       mutex_lock(&ctl->dsp->pwr_lock);
+
+       if (ctl->enabled)
+               ret = wm_coeff_write_acked_control(ctl, val);
+       else
+               ret = -EPERM;
+
+       mutex_unlock(&ctl->dsp->pwr_lock);
+
+       return ret;
+}
+
 static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
                                 void *buf, size_t len)
 {
-       struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
-       const struct wm_adsp_region *mem;
        struct wm_adsp *dsp = ctl->dsp;
        void *scratch;
        int ret;
        unsigned int reg;
 
-       mem = wm_adsp_find_region(dsp, alg_region->type);
-       if (!mem) {
-               adsp_err(dsp, "No base for region %x\n",
-                        alg_region->type);
-               return -EINVAL;
-       }
-
-       reg = ctl->alg_region.base + ctl->offset;
-       reg = wm_adsp_region_to_reg(mem, reg);
+       ret = wm_coeff_base_reg(ctl, &reg);
+       if (ret)
+               return ret;
 
        scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
        if (!scratch)
@@ -918,6 +1044,21 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
        return ret;
 }
 
+static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       /*
+        * Although it's not useful to read an acked control, we must satisfy
+        * user-side assumptions that all controls are readable and that a
+        * write of the same value should be filtered out (it's valid to send
+        * the same event number again to the firmware). We therefore return 0,
+        * meaning "no event" so valid event numbers will always be a change
+        */
+       ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
 struct wmfw_ctl_work {
        struct wm_adsp *dsp;
        struct wm_coeff_ctl *ctl;
@@ -967,30 +1108,35 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
        kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
        if (!kcontrol)
                return -ENOMEM;
-       kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 
        kcontrol->name = ctl->name;
        kcontrol->info = wm_coeff_info;
-       kcontrol->get = wm_coeff_get;
-       kcontrol->put = wm_coeff_put;
        kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
        kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
        kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
+       kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
 
-       ctl->bytes_ext.max = ctl->len;
-       ctl->bytes_ext.get = wm_coeff_tlv_get;
-       ctl->bytes_ext.put = wm_coeff_tlv_put;
+       switch (ctl->type) {
+       case WMFW_CTL_TYPE_ACKED:
+               kcontrol->get = wm_coeff_get_acked;
+               kcontrol->put = wm_coeff_put_acked;
+               break;
+       default:
+               kcontrol->get = wm_coeff_get;
+               kcontrol->put = wm_coeff_put;
 
-       kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len);
+               ctl->bytes_ext.max = ctl->len;
+               ctl->bytes_ext.get = wm_coeff_tlv_get;
+               ctl->bytes_ext.put = wm_coeff_tlv_put;
+               break;
+       }
 
-       ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1);
+       ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1);
        if (ret < 0)
                goto err_kcontrol;
 
        kfree(kcontrol);
 
-       ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name);
-
        return 0;
 
 err_kcontrol:
@@ -1035,6 +1181,27 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp)
        return 0;
 }
 
+static void wm_adsp_signal_event_controls(struct wm_adsp *dsp,
+                                         unsigned int event)
+{
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT)
+                       continue;
+
+               if (!ctl->enabled)
+                       continue;
+
+               ret = wm_coeff_write_acked_control(ctl, event);
+               if (ret)
+                       adsp_warn(dsp,
+                                 "Failed to send 0x%x event to alg 0x%x (%d)\n",
+                                 event, ctl->alg_region.alg, ret);
+       }
+}
+
 static void wm_adsp_ctl_work(struct work_struct *work)
 {
        struct wmfw_ctl_work *ctl_work = container_of(work,
@@ -1056,34 +1223,16 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
                                  const struct wm_adsp_alg_region *alg_region,
                                  unsigned int offset, unsigned int len,
                                  const char *subname, unsigned int subname_len,
-                                 unsigned int flags)
+                                 unsigned int flags, unsigned int type)
 {
        struct wm_coeff_ctl *ctl;
        struct wmfw_ctl_work *ctl_work;
        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       char *region_name;
+       const 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:
+       region_name = wm_adsp_mem_region_name(alg_region->type);
+       if (!region_name) {
                adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
                return -EINVAL;
        }
@@ -1139,6 +1288,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
        ctl->dsp = dsp;
 
        ctl->flags = flags;
+       ctl->type = type;
        ctl->offset = offset;
        ctl->len = len;
        ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
@@ -1149,6 +1299,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
 
        list_add(&ctl->list, &dsp->ctl_list);
 
+       if (flags & WMFW_CTL_FLAG_SYS)
+               return 0;
+
        ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
        if (!ctl_work) {
                ret = -ENOMEM;
@@ -1308,6 +1461,21 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
        adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
 }
 
+static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp,
+                               const struct wm_coeff_parsed_coeff *coeff_blk,
+                               unsigned int f_required,
+                               unsigned int f_illegal)
+{
+       if ((coeff_blk->flags & f_illegal) ||
+           ((coeff_blk->flags & f_required) != f_required)) {
+               adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n",
+                        coeff_blk->flags, coeff_blk->ctl_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
                               const struct wmfw_region *region)
 {
@@ -1324,6 +1492,28 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
                switch (coeff_blk.ctl_type) {
                case SNDRV_CTL_ELEM_TYPE_BYTES:
                        break;
+               case WMFW_CTL_TYPE_ACKED:
+                       if (coeff_blk.flags & WMFW_CTL_FLAG_SYS)
+                               continue;       /* ignore */
+
+                       ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+                                               WMFW_CTL_FLAG_VOLATILE |
+                                               WMFW_CTL_FLAG_WRITEABLE |
+                                               WMFW_CTL_FLAG_READABLE,
+                                               0);
+                       if (ret)
+                               return -EINVAL;
+                       break;
+               case WMFW_CTL_TYPE_HOSTEVENT:
+                       ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+                                               WMFW_CTL_FLAG_SYS |
+                                               WMFW_CTL_FLAG_VOLATILE |
+                                               WMFW_CTL_FLAG_WRITEABLE |
+                                               WMFW_CTL_FLAG_READABLE,
+                                               0);
+                       if (ret)
+                               return -EINVAL;
+                       break;
                default:
                        adsp_err(dsp, "Unknown control type: %d\n",
                                 coeff_blk.ctl_type);
@@ -1338,7 +1528,8 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
                                             coeff_blk.len,
                                             coeff_blk.name,
                                             coeff_blk.name_len,
-                                            coeff_blk.flags);
+                                            coeff_blk.flags,
+                                            coeff_blk.ctl_type);
                if (ret < 0)
                        adsp_err(dsp, "Failed to create control: %.*s, %d\n",
                                 coeff_blk.name_len, coeff_blk.name, ret);
@@ -1491,23 +1682,11 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                        reg = offset;
                        break;
                case WMFW_ADSP1_PM:
-                       region_name = "PM";
-                       reg = wm_adsp_region_to_reg(mem, offset);
-                       break;
                case WMFW_ADSP1_DM:
-                       region_name = "DM";
-                       reg = wm_adsp_region_to_reg(mem, offset);
-                       break;
                case WMFW_ADSP2_XM:
-                       region_name = "XM";
-                       reg = wm_adsp_region_to_reg(mem, offset);
-                       break;
                case WMFW_ADSP2_YM:
-                       region_name = "YM";
-                       reg = wm_adsp_region_to_reg(mem, offset);
-                       break;
                case WMFW_ADSP1_ZM:
-                       region_name = "ZM";
+                       region_name = wm_adsp_mem_region_name(type);
                        reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                default:
@@ -1750,7 +1929,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp1_alg[i].dm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0, 0);
+                                                    len, NULL, 0, 0,
+                                                    SNDRV_CTL_ELEM_TYPE_BYTES);
                        } else {
                                adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1770,7 +1950,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp1_alg[i].zm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0, 0);
+                                                    len, NULL, 0, 0,
+                                                    SNDRV_CTL_ELEM_TYPE_BYTES);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1861,7 +2042,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp2_alg[i].xm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0, 0);
+                                                    len, NULL, 0, 0,
+                                                    SNDRV_CTL_ELEM_TYPE_BYTES);
                        } else {
                                adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1881,7 +2063,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp2_alg[i].ym);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0, 0);
+                                                    len, NULL, 0, 0,
+                                                    SNDRV_CTL_ELEM_TYPE_BYTES);
                        } else {
                                adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1901,7 +2084,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                                len -= be32_to_cpu(adsp2_alg[i].zm);
                                len *= 4;
                                wm_adsp_create_control(dsp, alg_region, 0,
-                                                      len, NULL, 0, 0);
+                                                    len, NULL, 0, 0,
+                                                    SNDRV_CTL_ELEM_TYPE_BYTES);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -2114,7 +2298,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
        int ret;
        unsigned int val;
 
-       dsp->card = codec->component.card;
+       dsp->codec = codec;
 
        mutex_lock(&dsp->pwr_lock);
 
@@ -2325,8 +2509,6 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
        struct wm_adsp *dsp = &dsps[w->shift];
        struct wm_coeff_ctl *ctl;
 
-       dsp->card = codec->component.card;
-
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                wm_adsp2_set_dspclk(dsp, freq);
@@ -2393,14 +2575,22 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
 
                mutex_lock(&dsp->pwr_lock);
 
-               if (wm_adsp_fw[dsp->fw].num_caps != 0)
+               if (wm_adsp_fw[dsp->fw].num_caps != 0) {
                        ret = wm_adsp_buffer_init(dsp);
+                       if (ret < 0) {
+                               mutex_unlock(&dsp->pwr_lock);
+                               goto err;
+                       }
+               }
 
                mutex_unlock(&dsp->pwr_lock);
 
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
+               /* Tell the firmware to cleanup */
+               wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
+
                /* Log firmware state, it can be useful for analysis */
                wm_adsp2_show_fw_status(dsp);
 
@@ -2441,6 +2631,8 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);
 
 int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
 {
+       dsp->codec = codec;
+
        wm_adsp2_init_debugfs(dsp, codec);
 
        return snd_soc_add_codec_controls(codec,
index 362dd7ce60d8cd8f17ca8b911a209442b6eb288e..411d062c13f2a6f422a671215e86e4029a0c5caf 100644 (file)
@@ -44,7 +44,7 @@ struct wm_adsp {
        int type;
        struct device *dev;
        struct regmap *regmap;
-       struct snd_soc_card *card;
+       struct snd_soc_codec *codec;
 
        int base;
        int sysclk_reg;
@@ -110,18 +110,17 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
 
-extern int wm_adsp_compr_open(struct wm_adsp *dsp,
-                             struct snd_compr_stream *stream);
-extern int wm_adsp_compr_free(struct snd_compr_stream *stream);
-extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
-                                   struct snd_compr_params *params);
-extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
-                                 struct snd_compr_caps *caps);
-extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
-extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
-extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
-                                struct snd_compr_tstamp *tstamp);
-extern int wm_adsp_compr_copy(struct snd_compr_stream *stream,
-                             char __user *buf, size_t count);
+int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
+int wm_adsp_compr_free(struct snd_compr_stream *stream);
+int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
+                            struct snd_compr_params *params);
+int wm_adsp_compr_get_caps(struct snd_compr_stream *stream,
+                          struct snd_compr_caps *caps);
+int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd);
+int wm_adsp_compr_handle_irq(struct wm_adsp *dsp);
+int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
+                         struct snd_compr_tstamp *tstamp);
+int wm_adsp_compr_copy(struct snd_compr_stream *stream,
+                      char __user *buf, size_t count);
 
 #endif
index 7613d60d62ea32d6d639a065b75eb2656c70dae7..ec78b9da020fb169be6e8f7d84285efd39a0df58 100644 (file)
 #define WMFW_CTL_FLAG_WRITEABLE   0x0002
 #define WMFW_CTL_FLAG_READABLE    0x0001
 
+/* Non-ALSA coefficient types start at 0x1000 */
+#define WMFW_CTL_TYPE_ACKED       0x1000 /* acked control */
+#define WMFW_CTL_TYPE_HOSTEVENT   0x1001 /* event control */
+
 struct wmfw_header {
        char magic[4];
        __le32 len;
index 19bdcac71775a50134070960d51b995c06687e75..37f9b6201918348098194e6eb8da5460b7a09640 100644 (file)
@@ -40,6 +40,7 @@ config SND_SOC_FSL_SPDIF
        select REGMAP_MMIO
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC)
+       select BITREVERSE
        help
          Say Y if you want to add Sony/Philips Digital Interface (SPDIF)
          support for the Freescale CPUs.
index dffd549a0e2abdc05d0b218669d34ec13f136ee6..9998aea2359794fff4b9ccb82b7ab3ee375437aa 100644 (file)
@@ -183,7 +183,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_ops fsl_asoc_card_ops = {
+static const struct snd_soc_ops fsl_asoc_card_ops = {
        .hw_params = fsl_asoc_card_hw_params,
 };
 
index 201a70d1027a4a91bddd6dbc6e8d304071b3dd8d..1b60958e208000389d1fd1f347652c7d37abb3e7 100644 (file)
@@ -61,7 +61,7 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_ops imx_hifi_ops = {
+static const struct snd_soc_ops imx_hifi_ops = {
        .hw_params = imx_hifi_hw_params,
 };
 
index f608f8d23f3d9f3b1ce8a3a7f137a20e7922fe07..a385ff6bfa4b3acbc1809176cd23eb6d4e0c5eb6 100644 (file)
@@ -174,7 +174,7 @@ err:
        return ret;
 }
 
-static struct snd_soc_ops asoc_simple_card_ops = {
+static const struct snd_soc_ops asoc_simple_card_ops = {
        .startup = asoc_simple_card_startup,
        .shutdown = asoc_simple_card_shutdown,
        .hw_params = asoc_simple_card_hw_params,
index b9973a56bcb02f896b2a0273eabc7812428e71e3..fe3d3ca45b39b4aca80b52ec08f5463e64a3a323 100644 (file)
@@ -59,7 +59,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
        clk_disable_unprepare(dai_props->clk);
 }
 
-static struct snd_soc_ops asoc_simple_card_ops = {
+static const struct snd_soc_ops asoc_simple_card_ops = {
        .startup = asoc_simple_card_startup,
        .shutdown = asoc_simple_card_shutdown,
 };
index 26eb5a0a55754c43f94afe8a3403982b408d3e2b..fd5d1e0910382e94233702094658b6b868c71b83 100644 (file)
@@ -47,6 +47,7 @@ config SND_SOC_INTEL_SST_MATCH
 
 config SND_SOC_INTEL_HASWELL
        tristate
+       select SND_SOC_INTEL_SST_FIRMWARE
 
 config SND_SOC_INTEL_BAYTRAIL
        tristate
@@ -56,7 +57,6 @@ config SND_SOC_INTEL_HASWELL_MACH
        depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
        depends on DW_DMAC_CORE
        select SND_SOC_INTEL_SST
-       select SND_SOC_INTEL_SST_FIRMWARE
        select SND_SOC_INTEL_HASWELL
        select SND_SOC_RT5640
        help
@@ -138,7 +138,6 @@ config SND_SOC_INTEL_BROADWELL_MACH
                   I2C_DESIGNWARE_PLATFORM
        depends on DW_DMAC_CORE
        select SND_SOC_INTEL_SST
-       select SND_SOC_INTEL_SST_FIRMWARE
        select SND_SOC_INTEL_HASWELL
        select SND_SOC_RT286
        help
index 0838478c4c3f90cf716d2284541e688003c29e20..c7b3cbf92faf2508b4aee69734b3a335cf547dc5 100644 (file)
@@ -937,7 +937,7 @@ int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)
        struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
        int ssp_id;
 
-       dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
+       dev_dbg(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
 
        if (strcmp(id, "ssp0-port") == 0)
                ssp_id = SSP_MODEM;
index 25c6d87c818e7caf4bdd904b7b72d17887f58b25..f5a8050351b53a0fdfc60af61a176cf3e60b08a2 100644 (file)
@@ -771,6 +771,9 @@ static int sst_soc_prepare(struct device *dev)
        struct sst_data *drv = dev_get_drvdata(dev);
        struct snd_soc_pcm_runtime *rtd;
 
+       if (!drv->soc_card)
+               return 0;
+
        /* suspend all pcms first */
        snd_soc_suspend(drv->soc_card->dev);
        snd_soc_poweroff(drv->soc_card->dev);
@@ -793,6 +796,9 @@ static void sst_soc_complete(struct device *dev)
        struct sst_data *drv = dev_get_drvdata(dev);
        struct snd_soc_pcm_runtime *rtd;
 
+       if (!drv->soc_card)
+               return;
+
        /* restart SSPs */
        list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) {
                struct snd_soc_dai *dai = rtd->cpu_dai;
index 9b6e27385dc90742a37ae2e17a4eca4fe4aca2dd..f9ba71315e335021b34aa18b4030a29b861bcac1 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pm_qos.h>
 #include <linux/async.h>
 #include <linux/acpi.h>
+#include <linux/sysfs.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <asm/platform_sst_audio.h>
@@ -242,6 +243,32 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx,
 }
 EXPORT_SYMBOL_GPL(sst_alloc_drv_context);
 
+static ssize_t firmware_version_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->fw_version.type == 0 && ctx->fw_version.major == 0 &&
+           ctx->fw_version.minor == 0 && ctx->fw_version.build == 0)
+               return sprintf(buf, "FW not yet loaded\n");
+       else
+               return sprintf(buf, "v%02x.%02x.%02x.%02x\n",
+                              ctx->fw_version.type, ctx->fw_version.major,
+                              ctx->fw_version.minor, ctx->fw_version.build);
+
+}
+
+DEVICE_ATTR_RO(firmware_version);
+
+static const struct attribute *sst_fw_version_attrs[] = {
+       &dev_attr_firmware_version.attr,
+       NULL,
+};
+
+static const struct attribute_group sst_fw_version_attr_group = {
+       .attrs = (struct attribute **)sst_fw_version_attrs,
+};
+
 int sst_context_init(struct intel_sst_drv *ctx)
 {
        int ret = 0, i;
@@ -315,8 +342,19 @@ int sst_context_init(struct intel_sst_drv *ctx)
                dev_err(ctx->dev, "Firmware download failed:%d\n", ret);
                goto do_free_mem;
        }
+
+       ret = sysfs_create_group(&ctx->dev->kobj,
+                                &sst_fw_version_attr_group);
+       if (ret) {
+               dev_err(ctx->dev,
+                       "Unable to create sysfs\n");
+               goto err_sysfs;
+       }
+
        sst_register(ctx->dev);
        return 0;
+err_sysfs:
+       sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group);
 
 do_free_mem:
        destroy_workqueue(ctx->post_msg_wq);
@@ -330,6 +368,7 @@ void sst_context_cleanup(struct intel_sst_drv *ctx)
        pm_runtime_disable(ctx->dev);
        sst_unregister(ctx->dev);
        sst_set_fw_state_locked(ctx, SST_SHUTDOWN);
+       sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group);
        flush_scheduled_work();
        destroy_workqueue(ctx->post_msg_wq);
        pm_qos_remove_request(ctx->qos);
index 3f493862e98dd0bd26b9e1733c4b05b729c963f5..5c9a51cc77aa41e8efe123afc517a42867f16baf 100644 (file)
@@ -436,6 +436,7 @@ struct intel_sst_drv {
         */
        char firmware_name[FW_NAME_SIZE];
 
+       struct snd_sst_fw_version fw_version;
        struct sst_fw_save      *fw_save;
 };
 
index ba5c0d71720ab8548fddbb42cd79dd90c869abab..f4d92bbc5373c953a5e750210a4159ae6b6594dc 100644 (file)
@@ -416,6 +416,7 @@ static const struct dmi_system_id cht_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
                },
        },
+       { }
 };
 
 
@@ -451,6 +452,8 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = {
 static struct sst_acpi_mach sst_acpi_chv[] = {
        {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
                                                &chv_platform_data },
+       {"10EC5672", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
+                                               &chv_platform_data },
        {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
                                                &chv_platform_data },
        {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
index bfc889950bb2964abc4653afdc9cee9bc3bde248..374bb61c596d8f928c3b76ea33be0be1a3cf37d9 100644 (file)
@@ -236,6 +236,17 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx,
                retval = init->result;
                goto ret;
        }
+       dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n",
+                       init->fw_version.type, init->fw_version.major,
+                       init->fw_version.minor, init->fw_version.build);
+       dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n",
+                       init->build_info.date, init->build_info.time);
+
+       /* Save FW version */
+       sst_drv_ctx->fw_version.type = init->fw_version.type;
+       sst_drv_ctx->fw_version.major = init->fw_version.major;
+       sst_drv_ctx->fw_version.minor = init->fw_version.minor;
+       sst_drv_ctx->fw_version.build = init->fw_version.build;
 
 ret:
        sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0);
index 4ccc80e5e8cc0a78aa2cbb805f5ed94c160c5fdf..51bdeeecb7c842fdf8035716d3402a607a0ebf37 100644 (file)
@@ -104,7 +104,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
        sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type,
                        str_id, alloc_param.operation, 0);
 
-       dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
+       dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
                        str_id, pipe_id);
        ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
                        IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
@@ -415,7 +415,7 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
                str_info->status = STREAM_UN_INIT;
                mutex_unlock(&str_info->lock);
 
-               dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
+               dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
                                str_id, str_info->pipe_id);
                retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
                                IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
index 7ab14ce65a73bff98d42d51f4479d280aee72a17..260447da32b8709b5ff72799141b99775adba93b 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/kthread.h>
 #include <linux/firmware.h>
 #include <linux/io.h>
 #include <asm/div64.h>
@@ -338,7 +337,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context)
        spin_unlock_irqrestore(&sst->spinlock, flags);
 
        /* continue to send any remaining messages... */
-       kthread_queue_work(&ipc->kworker, &ipc->kwork);
+       schedule_work(&ipc->kwork);
 
        return IRQ_HANDLED;
 }
index 547e6705bf6dbc195ccb701ab39cb6735ec6c482..53c6b4cbb1e1494519f7c5b76b2051b7dcfc8cb7 100644 (file)
@@ -156,7 +156,7 @@ static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops bdw_rt5677_ops = {
+static const struct snd_soc_ops bdw_rt5677_ops = {
        .hw_params = bdw_rt5677_hw_params,
 };
 
index 7486a0022fdea1f6e06ff7be167f1b60ee558462..4d7e9decfa92e476af9f6dbc66454ec603ad1c85 100644 (file)
@@ -126,7 +126,7 @@ static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops broadwell_rt286_ops = {
+static const struct snd_soc_ops broadwell_rt286_ops = {
        .hw_params = broadwell_rt286_hw_params,
 };
 
@@ -220,10 +220,12 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
 };
 
 static int broadwell_suspend(struct snd_soc_card *card){
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
+
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               if (!strcmp(component->name, "i2c-INT343A:00")) {
+                       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               if (!strcmp(codec->component.name, "i2c-INT343A:00")) {
                        dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
                        rt286_mic_detect(codec, NULL);
                        break;
@@ -233,10 +235,12 @@ static int broadwell_suspend(struct snd_soc_card *card){
 }
 
 static int broadwell_resume(struct snd_soc_card *card){
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
+
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               if (!strcmp(component->name, "i2c-INT343A:00")) {
+                       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               if (!strcmp(codec->component.name, "i2c-INT343A:00")) {
                        dev_dbg(codec->dev, "enabling jack detect for resume.\n");
                        rt286_mic_detect(codec, &broadwell_headset);
                        break;
index 6532b8f0ab2fc475f09116d24dcf316170ce5618..1b4330cd273921a1f5f0ad393d6ac8b8b579425a 100644 (file)
@@ -30,6 +30,7 @@
 #define BXT_DIALOG_CODEC_DAI   "da7219-hifi"
 #define BXT_MAXIM_CODEC_DAI    "HiFi"
 #define DUAL_CHANNEL           2
+#define QUAD_CHANNEL           4
 
 static struct snd_soc_jack broxton_headset;
 
@@ -130,8 +131,8 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
         */
        ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset,
-                       NULL, 0);
+                       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                       &broxton_headset, NULL, 0);
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
@@ -182,6 +183,16 @@ static struct snd_pcm_hw_constraint_list constraints_channels = {
        .mask = 0,
 };
 
+static unsigned int channels_quad[] = {
+       QUAD_CHANNEL,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
+       .count = ARRAY_SIZE(channels_quad),
+       .list = channels_quad,
+       .mask = 0,
+};
+
 static int bxt_fe_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -248,7 +259,7 @@ static int broxton_da7219_hw_free(struct snd_pcm_substream *substream)
        return ret;
 }
 
-static struct snd_soc_ops broxton_da7219_ops = {
+static const struct snd_soc_ops broxton_da7219_ops = {
        .hw_params = broxton_da7219_hw_params,
        .hw_free = broxton_da7219_hw_free,
 };
@@ -258,7 +269,10 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
 {
        struct snd_interval *channels = hw_param_interval(params,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
-       channels->min = channels->max = DUAL_CHANNEL;
+       if (params_channels(params) == 2)
+               channels->min = channels->max = 2;
+       else
+               channels->min = channels->max = 4;
 
        return 0;
 }
@@ -267,9 +281,9 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       runtime->hw.channels_max = DUAL_CHANNEL;
+       runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                       &constraints_channels);
+                       &constraints_channels_quad);
 
        return snd_pcm_hw_constraint_list(substream->runtime, 0,
                        SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
@@ -295,7 +309,7 @@ static int broxton_refcap_startup(struct snd_pcm_substream *substream)
                        &constraints_16000);
 };
 
-static struct snd_soc_ops broxton_refcap_ops = {
+static const struct snd_soc_ops broxton_refcap_ops = {
        .startup = broxton_refcap_startup,
 };
 
@@ -348,7 +362,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
                .dynamic = 1,
                .ops = &broxton_refcap_ops,
        },
-       [BXT_DPCM_AUDIO_DMIC_CP]
+       [BXT_DPCM_AUDIO_DMIC_CP] =
        {
                .name = "Bxt Audio DMIC cap",
                .stream_name = "dmiccap",
index d610bdca160867bbc87dcbf88bc841021ecc7860..1309405b38085eb5c1dc90d6d52a56eb7573fcde 100644 (file)
@@ -181,7 +181,7 @@ static int broxton_rt298_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops broxton_rt298_ops = {
+static const struct snd_soc_ops broxton_rt298_ops = {
        .hw_params = broxton_rt298_hw_params,
 };
 
@@ -230,7 +230,7 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream)
                                SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops broxton_dmic_ops = {
+static const struct snd_soc_ops broxton_dmic_ops = {
        .startup = broxton_dmic_startup,
 };
 
index bff77a1f27fca127cd2a2ae0a5177915b7d1a65f..507a86a5eafe5646bb9731f865b85571eb6ffdfc 100644 (file)
@@ -57,9 +57,7 @@ struct byt_rt5640_private {
        struct clk *mclk;
 };
 
-static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
-                                       BYT_RT5640_DMIC_EN |
-                                       BYT_RT5640_MCLK_EN;
+static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN;
 
 static void log_quirks(struct device *dev)
 {
@@ -597,11 +595,11 @@ static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream)
                        SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
-static struct snd_soc_ops byt_rt5640_aif1_ops = {
+static const struct snd_soc_ops byt_rt5640_aif1_ops = {
        .startup = byt_rt5640_aif1_startup,
 };
 
-static struct snd_soc_ops byt_rt5640_be_ssp2_ops = {
+static const struct snd_soc_ops byt_rt5640_be_ssp2_ops = {
        .hw_params = byt_rt5640_aif1_hw_params,
 };
 
@@ -689,6 +687,10 @@ static bool is_valleyview(void)
        return true;
 }
 
+struct acpi_chan_package {   /* ACPICA seems to require 64 bit integers */
+       u64 aif_value;       /* 1: AIF1, 2: AIF2 */
+       u64 mclock_value;    /* usually 25MHz (0x17d7940), ignored */
+};
 
 static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 {
@@ -698,6 +700,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
        int i;
        int dai_index;
        struct byt_rt5640_private *priv;
+       bool is_bytcr = false;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
        if (!priv)
@@ -734,10 +737,61 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
                struct sst_platform_info *p_info = mach->pdata;
                const struct sst_res_info *res_info = p_info->res_info;
 
-               /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */
-               if (res_info->acpi_ipc_irq_index == 0) {
+               if (res_info->acpi_ipc_irq_index == 0)
+                       is_bytcr = true;
+       }
+
+       if (is_bytcr) {
+               /*
+                * Baytrail CR platforms may have CHAN package in BIOS, try
+                * to find relevant routing quirk based as done on Windows
+                * platforms. We have to read the information directly from the
+                * BIOS, at this stage the card is not created and the links
+                * with the codec driver/pdata are non-existent
+                */
+
+               struct acpi_chan_package chan_package;
+
+               /* format specified: 2 64-bit integers */
+               struct acpi_buffer format = {sizeof("NN"), "NN"};
+               struct acpi_buffer state = {0, NULL};
+               struct sst_acpi_package_context pkg_ctx;
+               bool pkg_found = false;
+
+               state.length = sizeof(chan_package);
+               state.pointer = &chan_package;
+
+               pkg_ctx.name = "CHAN";
+               pkg_ctx.length = 2;
+               pkg_ctx.format = &format;
+               pkg_ctx.state = &state;
+               pkg_ctx.data_valid = false;
+
+               pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx);
+               if (pkg_found) {
+                       if (chan_package.aif_value == 1) {
+                               dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n");
+                               byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF1;
+                       } else  if (chan_package.aif_value == 2) {
+                               dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n");
+                               byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2;
+                       } else {
+                               dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n");
+                               pkg_found = false;
+                       }
+               }
+
+               if (!pkg_found) {
+                       /* no BIOS indications, assume SSP0-AIF2 connection */
                        byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2;
                }
+
+               /* change defaults for Baytrail-CR capture */
+               byt_rt5640_quirk |= BYT_RT5640_IN1_MAP;
+               byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC;
+       } else {
+               byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP |
+                               BYT_RT5640_DMIC_EN);
        }
 
        /* check quirks before creating card */
index 35f591eab3c93111b32508b93afb47b52ea98074..2d24dc04b5977a3bc8534e7e53780f6fb9f83547 100644 (file)
@@ -219,11 +219,11 @@ static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream)
                        &constraints_48000);
 }
 
-static struct snd_soc_ops byt_rt5651_aif1_ops = {
+static const struct snd_soc_ops byt_rt5651_aif1_ops = {
        .startup = byt_rt5651_aif1_startup,
 };
 
-static struct snd_soc_ops byt_rt5651_be_ssp2_ops = {
+static const struct snd_soc_ops byt_rt5651_be_ssp2_ops = {
        .hw_params = byt_rt5651_aif1_hw_params,
 };
 
index cdcced9f32b6220eeeff12b22a4b43821375e3d1..742bc0d4e681646c969e4c9563decbb291843517 100644 (file)
@@ -204,11 +204,11 @@ static int cht_max98090_headset_init(struct snd_soc_component *component)
        return ts3a227e_enable_jack_detect(component, &ctx->jack);
 }
 
-static struct snd_soc_ops cht_aif1_ops = {
+static const struct snd_soc_ops cht_aif1_ops = {
        .startup = cht_aif1_startup,
 };
 
-static struct snd_soc_ops cht_be_ssp2_ops = {
+static const struct snd_soc_ops cht_be_ssp2_ops = {
        .hw_params = cht_aif1_hw_params,
 };
 
index 56056ed7fcfd1e90b48f96316e1750fd92e113df..f504a0e18f9136217c3aafa990258ac1c3e92376 100644 (file)
@@ -44,6 +44,7 @@ struct cht_acpi_card {
 struct cht_mc_private {
        struct snd_soc_jack jack;
        struct cht_acpi_card *acpi_card;
+       char codec_name[16];
 };
 
 static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
@@ -250,11 +251,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream)
                        SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
-static struct snd_soc_ops cht_aif1_ops = {
+static const struct snd_soc_ops cht_aif1_ops = {
        .startup = cht_aif1_startup,
 };
 
-static struct snd_soc_ops cht_be_ssp2_ops = {
+static const struct snd_soc_ops cht_be_ssp2_ops = {
        .hw_params = cht_aif1_hw_params,
 };
 
@@ -354,7 +355,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        int i;
        struct cht_mc_private *drv;
        struct snd_soc_card *card = snd_soc_cards[0].soc_card;
-       char codec_name[16];
        struct sst_acpi_mach *mach;
        const char *i2c_name = NULL;
        int dai_index = 0;
@@ -374,12 +374,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
        }
        card->dev = &pdev->dev;
        mach = card->dev->platform_data;
-       sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
+       sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
 
        /* set correct codec name */
        for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
                if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) {
-                       card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL);
+                       card->dai_link[i].codec_name = drv->codec_name;
                        dai_index = i;
                }
 
index df9d254baa1876e900ca7a41d5cf749c8493d2c1..e4d46d4360d7e88cfdac008e9804bb7fdb310e6f 100644 (file)
 #include <sound/jack.h>
 #include "../../codecs/rt5670.h"
 #include "../atom/sst-atom-controls.h"
+#include "../common/sst-acpi.h"
 
 /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
 #define CHT_PLAT_CLK_3_HZ      19200000
 #define CHT_CODEC_DAI  "rt5670-aif1"
 
 static struct snd_soc_jack cht_bsw_headset;
+static char cht_bsw_codec_name[16];
 
 /* Headset jack detection DAPM pins */
 static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
@@ -225,11 +227,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream)
                        SNDRV_PCM_HW_PARAM_RATE, 48000);
 }
 
-static struct snd_soc_ops cht_aif1_ops = {
+static const struct snd_soc_ops cht_aif1_ops = {
        .startup = cht_aif1_startup,
 };
 
-static struct snd_soc_ops cht_be_ssp2_ops = {
+static const struct snd_soc_ops cht_be_ssp2_ops = {
        .hw_params = cht_aif1_hw_params,
 };
 
@@ -292,10 +294,12 @@ static struct snd_soc_dai_link cht_dailink[] = {
 
 static int cht_suspend_pre(struct snd_soc_card *card)
 {
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
+
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               if (!strcmp(component->name, "i2c-10EC5670:00")) {
+                       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {
                        dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n");
                        rt5670_jack_suspend(codec);
                        break;
@@ -306,10 +310,12 @@ static int cht_suspend_pre(struct snd_soc_card *card)
 
 static int cht_resume_post(struct snd_soc_card *card)
 {
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
+
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               if (!strcmp(component->name, "i2c-10EC5670:00")) {
+                       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
-       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               if (!strcmp(codec->component.name, "i2c-10EC5670:00")) {
                        dev_dbg(codec->dev, "enabling jack detect for resume.\n");
                        rt5670_jack_resume(codec);
                        break;
@@ -335,9 +341,33 @@ static struct snd_soc_card snd_soc_card_cht = {
        .resume_post = cht_resume_post,
 };
 
+#define RT5672_I2C_DEFAULT     "i2c-10EC5670:00"
+
 static int snd_cht_mc_probe(struct platform_device *pdev)
 {
        int ret_val = 0;
+       struct sst_acpi_mach *mach = pdev->dev.platform_data;
+       const char *i2c_name;
+       int i;
+
+       strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT);
+
+       /* fixup codec name based on HID */
+       if (mach) {
+               i2c_name = sst_acpi_find_name_from_hid(mach->id);
+               if (i2c_name) {
+                       snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name),
+                                "i2c-%s", i2c_name);
+                       for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
+                               if (!strcmp(cht_dailink[i].codec_name,
+                                           RT5672_I2C_DEFAULT)) {
+                                       cht_dailink[i].codec_name =
+                                               cht_bsw_codec_name;
+                                       break;
+                               }
+                       }
+               }
+       }
 
        /* register the soc card */
        snd_soc_card_cht.dev = &pdev->dev;
index 863f1d5e2a2c97b9775ff84a9d43d985db9fb9b5..5e1ea0371c9097bf1c79737bc1892d7667479480 100644 (file)
@@ -81,7 +81,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops haswell_rt5640_ops = {
+static const struct snd_soc_ops haswell_rt5640_ops = {
        .hw_params = haswell_rt5640_hw_params,
 };
 
index 34f46c72a0e27cff8cd37108d27b71029cd088c6..4e08885f37aaf87ed55103e1a210deae9893ec0e 100644 (file)
@@ -81,9 +81,9 @@ static struct snd_soc_jack_zone mfld_zones[] = {
 };
 
 /* sound card controls */
-static const char *headset_switch_text[] = {"Earpiece", "Headset"};
+static const char * const headset_switch_text[] = {"Earpiece", "Headset"};
 
-static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"};
+static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"};
 
 static const struct soc_enum headset_enum =
        SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
index 25db5be7fdfade30fd2a084df5320ccd0f0179ec..fddd1cd12f1316206958328547300208bacc16b7 100644 (file)
@@ -332,7 +332,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops skylake_nau8825_ops = {
+static const struct snd_soc_ops skylake_nau8825_ops = {
        .hw_params = skylake_nau8825_hw_params,
 };
 
@@ -382,7 +382,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream)
                        SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops skylake_dmic_ops = {
+static const struct snd_soc_ops skylake_dmic_ops = {
        .startup = skylake_dmic_startup,
 };
 
@@ -416,7 +416,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
                                &constraints_16000);
 }
 
-static struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylaye_refcap_ops = {
        .startup = skylake_refcap_startup,
 };
 
index 69c5d5da4e86a6f5d6b3934ee8a0c3e844cd7fdf..8ab865ee0cad7ce13d6c45bf4e361fa1115023b5 100644 (file)
@@ -394,7 +394,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops skylake_nau8825_ops = {
+static const struct snd_soc_ops skylake_nau8825_ops = {
        .hw_params = skylake_nau8825_hw_params,
 };
 
@@ -430,7 +430,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream)
                        SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops skylake_dmic_ops = {
+static const struct snd_soc_ops skylake_dmic_ops = {
        .startup = skylake_dmic_startup,
 };
 
@@ -464,7 +464,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream)
                        &constraints_16000);
 }
 
-static struct snd_soc_ops skylaye_refcap_ops = {
+static const struct snd_soc_ops skylaye_refcap_ops = {
        .startup = skylake_refcap_startup,
 };
 
index 88c61e8cb87f5e505df51eca34e2a6c88e321e96..dc5c3611a6ff6417f197a493e63cc5e251b8fe0d 100644 (file)
@@ -250,7 +250,7 @@ static int skylake_rt286_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops skylake_rt286_ops = {
+static const struct snd_soc_ops skylake_rt286_ops = {
        .hw_params = skylake_rt286_hw_params,
 };
 
@@ -289,7 +289,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream)
                        SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
 }
 
-static struct snd_soc_ops skylake_dmic_ops = {
+static const struct snd_soc_ops skylake_dmic_ops = {
        .startup = skylake_dmic_startup,
 };
 
index 012742299dd532407b4d4859b89a74d09b262d0b..214e000667ae0a2725f951e0956a39dbc37d8f10 100644 (file)
 #include <linux/stddef.h>
 #include <linux/acpi.h>
 
-/* translation fron HID to I2C name, needed for DAI codec_name */
+struct sst_acpi_package_context {
+       char *name;           /* package name */
+       int length;           /* number of elements */
+       struct acpi_buffer *format;
+       struct acpi_buffer *state;
+       bool data_valid;
+};
+
 #if IS_ENABLED(CONFIG_ACPI)
+/* translation fron HID to I2C name, needed for DAI codec_name */
 const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]);
+bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
+                                   struct sst_acpi_package_context *ctx);
 #else
 static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
 {
        return NULL;
 }
+static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
+                                          struct sst_acpi_package_context *ctx)
+{
+       return false;
+}
 #endif
 
 /* acpi match */
index 6c672ac79cce7b3b12e1a7cb65fdb8e8c4456f15..62f3a8e0ec87696389d46c7824297b5e36fce188 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/kthread.h>
 #include <sound/asound.h>
 
 #include "sst-dsp.h"
@@ -109,10 +108,9 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header,
                ipc->ops.tx_data_copy(msg, tx_data, tx_bytes);
 
        list_add_tail(&msg->list, &ipc->tx_list);
+       schedule_work(&ipc->kwork);
        spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
 
-       kthread_queue_work(&ipc->kworker, &ipc->kwork);
-
        if (wait)
                return tx_wait_done(ipc, msg, rx_data);
        else
@@ -156,42 +154,56 @@ free_mem:
        return -ENOMEM;
 }
 
-static void ipc_tx_msgs(struct kthread_work *work)
+static void ipc_tx_msgs(struct work_struct *work)
 {
        struct sst_generic_ipc *ipc =
                container_of(work, struct sst_generic_ipc, kwork);
        struct ipc_message *msg;
-       unsigned long flags;
 
-       spin_lock_irqsave(&ipc->dsp->spinlock, flags);
+       spin_lock_irq(&ipc->dsp->spinlock);
 
-       if (list_empty(&ipc->tx_list) || ipc->pending) {
-               spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
-               return;
-       }
-
-       /* if the DSP is busy, we will TX messages after IRQ.
-        * also postpone if we are in the middle of procesing completion irq*/
-       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;
-       }
+       while (!list_empty(&ipc->tx_list) && !ipc->pending) {
+               /* if the DSP is busy, we will TX messages after IRQ.
+                * also postpone if we are in the middle of processing
+                * completion irq
+                */
+               if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) {
+                       dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n");
+                       break;
+               }
 
-       msg = list_first_entry(&ipc->tx_list, struct ipc_message, list);
-       list_move(&msg->list, &ipc->rx_list);
+               msg = list_first_entry(&ipc->tx_list, struct ipc_message, list);
+               list_move(&msg->list, &ipc->rx_list);
 
-       if (ipc->ops.tx_msg != NULL)
-               ipc->ops.tx_msg(ipc, msg);
+               if (ipc->ops.tx_msg != NULL)
+                       ipc->ops.tx_msg(ipc, msg);
+       }
 
-       spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
+       spin_unlock_irq(&ipc->dsp->spinlock);
 }
 
 int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
        void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
 {
-       return ipc_tx_message(ipc, header, tx_data, tx_bytes,
+       int ret;
+
+       /*
+        * DSP maybe in lower power active state, so
+        * check if the DSP supports DSP lp On method
+        * if so invoke that before sending IPC
+        */
+       if (ipc->ops.check_dsp_lp_on)
+               if (ipc->ops.check_dsp_lp_on(ipc->dsp, true))
+                       return -EIO;
+
+       ret = ipc_tx_message(ipc, header, tx_data, tx_bytes,
                rx_data, rx_bytes, 1);
+
+       if (ipc->ops.check_dsp_lp_on)
+               if (ipc->ops.check_dsp_lp_on(ipc->dsp, false))
+                       return -EIO;
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait);
 
@@ -203,6 +215,14 @@ int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
 }
 EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait);
 
+int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header,
+       void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
+{
+       return ipc_tx_message(ipc, header, tx_data, tx_bytes,
+               rx_data, rx_bytes, 1);
+}
+EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm);
+
 struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
        u64 header)
 {
@@ -280,19 +300,7 @@ int sst_ipc_init(struct sst_generic_ipc *ipc)
        if (ret < 0)
                return -ENOMEM;
 
-       /* start the IPC message thread */
-       kthread_init_worker(&ipc->kworker);
-       ipc->tx_thread = kthread_run(kthread_worker_fn,
-                                       &ipc->kworker, "%s",
-                                       dev_name(ipc->dev));
-       if (IS_ERR(ipc->tx_thread)) {
-               dev_err(ipc->dev, "error: failed to create message TX task\n");
-               ret = PTR_ERR(ipc->tx_thread);
-               kfree(ipc->msg);
-               return ret;
-       }
-
-       kthread_init_work(&ipc->kwork, ipc_tx_msgs);
+       INIT_WORK(&ipc->kwork, ipc_tx_msgs);
        return 0;
 }
 EXPORT_SYMBOL_GPL(sst_ipc_init);
@@ -301,8 +309,7 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc)
 {
        int i;
 
-       if (ipc->tx_thread)
-               kthread_stop(ipc->tx_thread);
+       cancel_work_sync(&ipc->kwork);
 
        if (ipc->msg) {
                for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
index ceb7e468a3fa6db4e04c77ff3a9d7e1ffc83d840..7ed42a640ad64fe23e2b1363985d7ebf59271fd0 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/list.h>
 #include <linux/workqueue.h>
 #include <linux/sched.h>
-#include <linux/kthread.h>
 
 #define IPC_MAX_MAILBOX_BYTES  256
 
@@ -52,6 +51,7 @@ struct sst_plat_ipc_ops {
        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);
+       int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state);
 };
 
 /* SST generic IPC data */
@@ -65,8 +65,7 @@ struct sst_generic_ipc {
        struct list_head empty_list;
        wait_queue_head_t wait_txq;
        struct task_struct *tx_thread;
-       struct kthread_worker kworker;
-       struct kthread_work kwork;
+       struct work_struct kwork;
        bool pending;
        struct ipc_message *msg;
        int tx_data_max_size;
@@ -81,6 +80,9 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
 int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
        void *tx_data, size_t tx_bytes);
 
+int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header,
+       void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes);
+
 struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
        u64 header);
 
index 789843307a4950ad503d3cabda82300489d8e8d0..1070f3ad23e50e1e495824ca13f8d7176ca0b05e 100644 (file)
@@ -77,5 +77,62 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
 }
 EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
 
+static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level,
+                                       void *context, void **ret)
+{
+       struct acpi_device *adev;
+       acpi_status status = AE_OK;
+       struct sst_acpi_package_context *pkg_ctx = context;
+
+       pkg_ctx->data_valid = false;
+
+       if (acpi_bus_get_device(handle, &adev))
+               return AE_OK;
+
+       if (adev->status.present && adev->status.functional) {
+               struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+               union acpi_object  *myobj = NULL;
+
+               status = acpi_evaluate_object_typed(handle, pkg_ctx->name,
+                                               NULL, &buffer,
+                                               ACPI_TYPE_PACKAGE);
+               if (ACPI_FAILURE(status))
+                       return AE_OK;
+
+               myobj = buffer.pointer;
+               if (!myobj || myobj->package.count != pkg_ctx->length) {
+                       kfree(buffer.pointer);
+                       return AE_OK;
+               }
+
+               status = acpi_extract_package(myobj,
+                                       pkg_ctx->format, pkg_ctx->state);
+               if (ACPI_FAILURE(status)) {
+                       kfree(buffer.pointer);
+                       return AE_OK;
+               }
+
+               kfree(buffer.pointer);
+               pkg_ctx->data_valid = true;
+               return AE_CTRL_TERMINATE;
+       }
+
+       return AE_OK;
+}
+
+bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
+                               struct sst_acpi_package_context *ctx)
+{
+       acpi_status status;
+
+       status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL);
+
+       if (ACPI_FAILURE(status) || !ctx->data_valid)
+               return false;
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel Common ACPI Match module");
index e432a31fd9f2cbcd7a4f126bc32c048e2ba0a4ee..a3459d1682a6bd6bb6c9ab17abb5b04633dbadfc 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/platform_device.h>
-#include <linux/kthread.h>
 #include <linux/firmware.h>
 #include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
@@ -818,7 +817,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context)
        spin_unlock_irqrestore(&sst->spinlock, flags);
 
        /* continue to send any remaining messages... */
-       kthread_queue_work(&ipc->kworker, &ipc->kwork);
+       schedule_work(&ipc->kwork);
 
        return IRQ_HANDLED;
 }
index 1d251d59bcb9bbb4a20cebb2e4b53866cfa119c7..1f9f33d34000b13f752c875680038383c48561a4 100644 (file)
@@ -43,6 +43,9 @@
 
 #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
 
+/* Delay before scheduling D0i3 entry */
+#define BXT_D0I3_DELAY 5000
+
 static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
 {
         return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
@@ -288,6 +291,141 @@ sst_load_base_firmware_failed:
        return ret;
 }
 
+/*
+ * Decide the D0i3 state that can be targeted based on the usecase
+ * ref counts and DSP state
+ *
+ * Decision Matrix:  (X= dont care; state = target state)
+ *
+ * DSP state != SKL_DSP_RUNNING ; state = no d0i3
+ *
+ * DSP state == SKL_DSP_RUNNING , the following matrix applies
+ * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3
+ * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3
+ * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3
+ * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3
+ */
+static int bxt_d0i3_target_state(struct sst_dsp *ctx)
+{
+       struct skl_sst *skl = ctx->thread_context;
+       struct skl_d0i3_data *d0i3 = &skl->d0i3;
+
+       if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING)
+               return SKL_DSP_D0I3_NONE;
+
+       if (d0i3->non_d0i3)
+               return SKL_DSP_D0I3_NONE;
+       else if (d0i3->streaming)
+               return SKL_DSP_D0I3_STREAMING;
+       else if (d0i3->non_streaming)
+               return SKL_DSP_D0I3_NON_STREAMING;
+       else
+               return SKL_DSP_D0I3_NONE;
+}
+
+static void bxt_set_dsp_D0i3(struct work_struct *work)
+{
+       int ret;
+       struct skl_ipc_d0ix_msg msg;
+       struct skl_sst *skl = container_of(work,
+                       struct skl_sst, d0i3.work.work);
+       struct sst_dsp *ctx = skl->dsp;
+       struct skl_d0i3_data *d0i3 = &skl->d0i3;
+       int target_state;
+
+       dev_dbg(ctx->dev, "In %s:\n", __func__);
+
+       /* D0i3 entry allowed only if core 0 alone is running */
+       if (skl_dsp_get_enabled_cores(ctx) !=  SKL_DSP_CORE0_MASK) {
+               dev_warn(ctx->dev,
+                               "D0i3 allowed when only core0 running:Exit\n");
+               return;
+       }
+
+       target_state = bxt_d0i3_target_state(ctx);
+       if (target_state == SKL_DSP_D0I3_NONE)
+               return;
+
+       msg.instance_id = 0;
+       msg.module_id = 0;
+       msg.wake = 1;
+       msg.streaming = 0;
+       if (target_state == SKL_DSP_D0I3_STREAMING)
+               msg.streaming = 1;
+
+       ret =  skl_ipc_set_d0ix(&skl->ipc, &msg);
+
+       if (ret < 0) {
+               dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n");
+               return;
+       }
+
+       /* Set Vendor specific register D0I3C.I3 to enable D0i3*/
+       if (skl->update_d0i3c)
+               skl->update_d0i3c(skl->dev, true);
+
+       d0i3->state = target_state;
+       skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3;
+}
+
+static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx)
+{
+       struct skl_sst *skl = ctx->thread_context;
+       struct skl_d0i3_data *d0i3 = &skl->d0i3;
+
+       /* Schedule D0i3 only if the usecase ref counts are appropriate */
+       if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) {
+
+               dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__);
+
+               schedule_delayed_work(&d0i3->work,
+                               msecs_to_jiffies(BXT_D0I3_DELAY));
+       }
+
+       return 0;
+}
+
+static int bxt_set_dsp_D0i0(struct sst_dsp *ctx)
+{
+       int ret;
+       struct skl_ipc_d0ix_msg msg;
+       struct skl_sst *skl = ctx->thread_context;
+
+       dev_dbg(ctx->dev, "In %s:\n", __func__);
+
+       /* First Cancel any pending attempt to put DSP to D0i3 */
+       cancel_delayed_work_sync(&skl->d0i3.work);
+
+       /* If DSP is currently in D0i3, bring it to D0i0 */
+       if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3)
+               return 0;
+
+       dev_dbg(ctx->dev, "Set DSP to D0i0\n");
+
+       msg.instance_id = 0;
+       msg.module_id = 0;
+       msg.streaming = 0;
+       msg.wake = 0;
+
+       if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING)
+               msg.streaming = 1;
+
+       /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/
+       if (skl->update_d0i3c)
+               skl->update_d0i3c(skl->dev, false);
+
+       ret =  skl_ipc_set_d0ix(&skl->ipc, &msg);
+       if (ret < 0) {
+               dev_err(ctx->dev, "Failed to set DSP to D0i0\n");
+               return ret;
+       }
+
+       skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
+       skl->d0i3.state = SKL_DSP_D0I3_NONE;
+
+       return 0;
+}
+
 static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
 {
        struct skl_sst *skl = ctx->thread_context;
@@ -414,6 +552,8 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
 static struct skl_dsp_fw_ops bxt_fw_ops = {
        .set_state_D0 = bxt_set_dsp_D0,
        .set_state_D3 = bxt_set_dsp_D3,
+       .set_state_D0i3 = bxt_schedule_dsp_D0i3,
+       .set_state_D0i0 = bxt_set_dsp_D0i0,
        .load_fw = bxt_load_base_firmware,
        .get_fw_errcode = bxt_get_errorcode,
        .load_library = bxt_load_library,
@@ -470,10 +610,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
        if (ret)
                return ret;
 
+       /* set the D0i3 check */
+       skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
+
        skl->cores.count = 2;
        skl->boot_complete = false;
        init_waitqueue_head(&skl->boot_wait);
        skl->is_first_boot = true;
+       INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
+       skl->d0i3.state = SKL_DSP_D0I3_NONE;
 
        if (dsp)
                *dsp = skl;
index 805b7f2173f3ec6163d9de9728d0b099d9a3a9a1..e79cbcf6e4629e970f00db484df9433ab9500657 100644 (file)
@@ -294,6 +294,33 @@ int skl_free_dsp(struct skl *skl)
        return 0;
 }
 
+/*
+ * In the case of "suspend_active" i.e, the Audio IP being active
+ * during system suspend, immediately excecute any pending D0i3 work
+ * before suspending. This is needed for the IP to work in low power
+ * mode during system suspend. In the case of normal suspend, cancel
+ * any pending D0i3 work.
+ */
+int skl_suspend_late_dsp(struct skl *skl)
+{
+       struct skl_sst *ctx = skl->skl_sst;
+       struct delayed_work *dwork;
+
+       if (!ctx)
+               return 0;
+
+       dwork = &ctx->d0i3.work;
+
+       if (dwork->work.func) {
+               if (skl->supend_active)
+                       flush_delayed_work(dwork);
+               else
+                       cancel_delayed_work_sync(dwork);
+       }
+
+       return 0;
+}
+
 int skl_suspend_dsp(struct skl *skl)
 {
        struct skl_sst *ctx = skl->skl_sst;
@@ -500,16 +527,14 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
 int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
 {
        struct skl_dma_control *dma_ctrl;
-       struct skl_i2s_config_blob config_blob;
        struct skl_ipc_large_config_msg msg = {0};
        int err = 0;
 
 
        /*
-        * if blob size is same as capablity size, then no dma control
-        * present so return
+        * if blob size zero, then return
         */
-       if (mconfig->formats_config.caps_size == sizeof(config_blob))
+       if (mconfig->formats_config.caps_size == 0)
                return 0;
 
        msg.large_param_id = DMA_CONTROL_ID;
@@ -523,7 +548,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
        dma_ctrl->node_id = skl_get_node_id(ctx, mconfig);
 
        /* size in dwords */
-       dma_ctrl->config_length = sizeof(config_blob) / 4;
+       dma_ctrl->config_length = mconfig->formats_config.caps_size / 4;
 
        memcpy(dma_ctrl->config_data, mconfig->formats_config.caps,
                                mconfig->formats_config.caps_size);
@@ -531,7 +556,6 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
        err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl);
 
        kfree(dma_ctrl);
-
        return err;
 }
 
@@ -1042,7 +1066,8 @@ int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe)
        dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id);
 
        ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages,
-                               pipe->pipe_priority, pipe->ppl_id);
+                               pipe->pipe_priority, pipe->ppl_id,
+                               pipe->lp_mode);
        if (ret < 0) {
                dev_err(ctx->dev, "Failed to create pipeline\n");
                return ret;
index 58c728662600455dcd9d9fbf442687728ea1bf7d..84b5101e6ca691df0e0896b59a95e07a55e3b5e7 100644 (file)
@@ -144,6 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
        struct hdac_ext_stream *stream;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct skl_dma_params *dma_params;
+       struct skl *skl = get_skl_ctx(dai->dev);
+       struct skl_module_cfg *mconfig;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
@@ -177,6 +179,9 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
        skl_set_suspend_active(substream, dai, true);
        snd_pcm_set_sync(substream);
 
+       mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+       skl_tplg_d0i3_get(skl, mconfig->d0i3_caps);
+
        return 0;
 }
 
@@ -302,6 +307,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
        struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
        struct skl_dma_params *dma_params = NULL;
        struct skl *skl = ebus_to_skl(ebus);
+       struct skl_module_cfg *mconfig;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
@@ -325,6 +331,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
                skl->skl_sst->miscbdcg_disabled = false;
        }
 
+       mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+       skl_tplg_d0i3_put(skl, mconfig->d0i3_caps);
+
        kfree(dma_params);
 }
 
@@ -1031,10 +1040,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
                        (struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
+       struct hdac_ext_bus *ebus = get_bus_ctx(substream);
        unsigned int pos;
 
-       /* use the position buffer as default */
-       pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
+       /*
+        * Use DPIB for Playback stream as the periodic DMA Position-in-
+        * Buffer Writes may be scheduled at the same time or later than
+        * the MSI and does not guarantee to reflect the Position of the
+        * last buffer that was transferred. Whereas DPIB register in
+        * HAD space reflects the actual data that is transferred.
+        * Use the position buffer for capture, as DPIB write gets
+        * completed earlier than the actual data written to the DDR.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
+                               (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                               hdac_stream(hstream)->index));
+       else
+               pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
 
        if (pos >= hdac_stream(hstream)->bufsize)
                pos = 0;
@@ -1197,6 +1220,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
                        return ret;
                }
                skl_populate_modules(skl);
+               skl->skl_sst->update_d0i3c = skl_update_d0i3c;
        }
        pm_runtime_mark_last_busy(platform->dev);
        pm_runtime_put_autosuspend(platform->dev);
index efa2532114ba82d593b218b64209b95e9b50a315..c9f6d87381dbe97e6d5ed3d5b5c6423aa646aa92 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <linux/device.h>
 #include <linux/mm.h>
-#include <linux/kthread.h>
 #include <linux/delay.h>
 #include "../common/sst-dsp.h"
 #include "../common/sst-dsp-priv.h"
index b9e71d051fb11759d67b1ee7650adab7b9087d44..7c272ba0f4b517da8faeb590f5265ed6ec602dfd 100644 (file)
@@ -126,11 +126,21 @@ struct sst_dsp_device;
 #define SKL_ADSPCS_CPA_SHIFT           24
 #define SKL_ADSPCS_CPA_MASK(cm)                ((cm) << SKL_ADSPCS_CPA_SHIFT)
 
+/* DSP Core state */
 enum skl_dsp_states {
        SKL_DSP_RUNNING = 1,
+       /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */
+       SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/
        SKL_DSP_RESET,
 };
 
+/* D0i3 substates */
+enum skl_dsp_d0i3_states {
+       SKL_DSP_D0I3_NONE = -1, /* No D0i3 */
+       SKL_DSP_D0I3_NON_STREAMING = 0,
+       SKL_DSP_D0I3_STREAMING = 1,
+};
+
 struct skl_dsp_fw_ops {
        int (*load_fw)(struct sst_dsp  *ctx);
        /* FW module parser/loader */
@@ -139,6 +149,8 @@ struct skl_dsp_fw_ops {
        int (*parse_fw)(struct sst_dsp *ctx);
        int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
        int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
+       int (*set_state_D0i3)(struct sst_dsp *ctx);
+       int (*set_state_D0i0)(struct sst_dsp *ctx);
        unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
        int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name);
        int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
index 797cf40532352c22a1adc573dd1aa1db292e726e..e1391dfbc9e919960ef0e2a4cb11e4ce20b4c42f 100644 (file)
 #define IPC_INSTANCE_ID(x)             (((x) & IPC_INSTANCE_ID_MASK) \
                                        << IPC_INSTANCE_ID_SHIFT)
 
+#define IPC_PPL_LP_MODE_SHIFT           0
+#define IPC_PPL_LP_MODE_MASK            0x1
+#define IPC_PPL_LP_MODE(x)              (((x) & IPC_PPL_LP_MODE_MASK) \
+                                       << IPC_PPL_LP_MODE_SHIFT)
+
 /* Set pipeline state message */
 #define IPC_PPL_STATE_SHIFT            0
 #define IPC_PPL_STATE_MASK             0x1F
                                        << IPC_INITIAL_BLOCK_SHIFT)
 #define IPC_INITIAL_BLOCK_CLEAR                ~(IPC_INITIAL_BLOCK_MASK \
                                          << IPC_INITIAL_BLOCK_SHIFT)
+/* Set D0ix IPC extension register */
+#define IPC_D0IX_WAKE_SHIFT            0
+#define IPC_D0IX_WAKE_MASK             0x1
+#define IPC_D0IX_WAKE(x)               (((x) & IPC_D0IX_WAKE_MASK) \
+                                       << IPC_D0IX_WAKE_SHIFT)
+
+#define IPC_D0IX_STREAMING_SHIFT       1
+#define IPC_D0IX_STREAMING_MASK                0x1
+#define IPC_D0IX_STREAMING(x)          (((x) & IPC_D0IX_STREAMING_MASK) \
+                                       << IPC_D0IX_STREAMING_SHIFT)
+
 
 enum skl_ipc_msg_target {
        IPC_FW_GEN_MSG = 0,
@@ -258,7 +274,8 @@ enum skl_ipc_module_msg {
        IPC_MOD_LARGE_CONFIG_SET = 4,
        IPC_MOD_BIND = 5,
        IPC_MOD_UNBIND = 6,
-       IPC_MOD_SET_DX = 7
+       IPC_MOD_SET_DX = 7,
+       IPC_MOD_SET_D0IX = 8
 };
 
 static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
@@ -289,6 +306,23 @@ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
                header->primary | SKL_ADSP_REG_HIPCI_BUSY);
 }
 
+int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state)
+{
+       int ret;
+
+       /* check D0i3 support */
+       if (!dsp->fw_ops.set_state_D0i0)
+               return 0;
+
+       /* Attempt D0i0 or D0i3 based on state */
+       if (state)
+               ret = dsp->fw_ops.set_state_D0i0(dsp);
+       else
+               ret = dsp->fw_ops.set_state_D0i3(dsp);
+
+       return ret;
+}
+
 static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc,
                                u64 ipc_header)
 {
@@ -464,7 +498,7 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context)
        skl_ipc_int_enable(dsp);
 
        /* continue to send any remaining messages... */
-       kthread_queue_work(&ipc->kworker, &ipc->kwork);
+       schedule_work(&ipc->kwork);
 
        return IRQ_HANDLED;
 }
@@ -547,7 +581,7 @@ void skl_ipc_free(struct sst_generic_ipc *ipc)
 }
 
 int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
-               u16 ppl_mem_size, u8 ppl_type, u8 instance_id)
+               u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode)
 {
        struct skl_ipc_header header = {0};
        u64 *ipc_header = (u64 *)(&header);
@@ -560,6 +594,8 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
        header.primary |= IPC_PPL_TYPE(ppl_type);
        header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size);
 
+       header.extension = IPC_PPL_LP_MODE(lp_mode);
+
        dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
        ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0);
        if (ret < 0) {
@@ -931,3 +967,32 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
        return ret;
 }
 EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library);
+
+int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg)
+{
+       struct skl_ipc_header header = {0};
+       u64 *ipc_header = (u64 *)(&header);
+       int ret;
+
+       header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
+       header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST);
+       header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX);
+       header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id);
+       header.primary |= IPC_MOD_ID(msg->module_id);
+
+       header.extension = IPC_D0IX_WAKE(msg->wake);
+       header.extension |= IPC_D0IX_STREAMING(msg->streaming);
+
+       dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__,
+                       header.primary, header.extension);
+
+       /*
+        * Use the nopm IPC here as we dont want it checking for D0iX
+        */
+       ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0);
+       if (ret < 0)
+               dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix);
index 0334ed4af0312a89eef15a09f05a67c88465272b..cc40341233fa63c952534a3c9287b378b5f88d99 100644 (file)
@@ -16,7 +16,6 @@
 #ifndef __SKL_IPC_H
 #define __SKL_IPC_H
 
-#include <linux/kthread.h>
 #include <linux/irqreturn.h>
 #include "../common/sst-ipc.h"
 
@@ -53,6 +52,23 @@ struct skl_dsp_cores {
        int usage_count[SKL_DSP_CORES_MAX];
 };
 
+/**
+ * skl_d0i3_data: skl D0i3 counters data struct
+ *
+ * @streaming: Count of usecases that can attempt streaming D0i3
+ * @non_streaming: Count of usecases that can attempt non-streaming D0i3
+ * @non_d0i3: Count of usecases that cannot attempt D0i3
+ * @state: current state
+ * @work: D0i3 worker thread
+ */
+struct skl_d0i3_data {
+       int streaming;
+       int non_streaming;
+       int non_d0i3;
+       enum skl_dsp_d0i3_states state;
+       struct delayed_work work;
+};
+
 struct skl_sst {
        struct device *dev;
        struct sst_dsp *dsp;
@@ -83,6 +99,11 @@ struct skl_sst {
 
        /* tplg manifest */
        struct skl_dfw_manifest manifest;
+
+       /* Callback to update D0i3C register */
+       void (*update_d0i3c)(struct device *dev, bool enable);
+
+       struct skl_d0i3_data d0i3;
 };
 
 struct skl_ipc_init_instance_msg {
@@ -111,6 +132,13 @@ struct skl_ipc_large_config_msg {
        u32 param_data_size;
 };
 
+struct skl_ipc_d0ix_msg {
+       u32 module_id;
+       u32 instance_id;
+       u8 streaming;
+       u8 wake;
+};
+
 #define SKL_IPC_BOOT_MSECS             3000
 
 #define SKL_IPC_D3_MASK        0
@@ -119,7 +147,7 @@ struct skl_ipc_large_config_msg {
 irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context);
 
 int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc,
-               u16 ppl_mem_size, u8 ppl_type, u8 instance_id);
+               u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode);
 
 int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id);
 
@@ -155,6 +183,11 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
 int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
                        u8 dma_id, u8 table_id);
 
+int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc,
+               struct skl_ipc_d0ix_msg *msg);
+
+int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state);
+
 void skl_ipc_int_enable(struct sst_dsp *dsp);
 void skl_ipc_op_int_enable(struct sst_dsp *ctx);
 void skl_ipc_op_int_disable(struct sst_dsp *ctx);
index 8dc03039b3113fa691626021ec4917a0155cf7e0..ea162fbf68e5b3038f99f1c7ef0ba24590e22c41 100644 (file)
@@ -179,7 +179,7 @@ static inline int skl_getid_32(struct uuid_module *module, u64 *val,
                index = ffz(mask_val);
                pvt_id = index + word1_mask + word2_mask;
                if (pvt_id <= (max_inst - 1)) {
-                       *val |= 1 << (index + word1_mask);
+                       *val |= 1ULL << (index + word1_mask);
                        return pvt_id;
                }
        }
index b5b1934d85504e328c0821405386eb2f22e85675..bd313c907b20df470a8c7727f8169c036fae25b9 100644 (file)
 #define SKL_IN_DIR_BIT_MASK            BIT(0)
 #define SKL_PIN_COUNT_MASK             GENMASK(7, 4)
 
+void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
+{
+       struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
+
+       switch (caps) {
+       case SKL_D0I3_NONE:
+               d0i3->non_d0i3++;
+               break;
+
+       case SKL_D0I3_STREAMING:
+               d0i3->streaming++;
+               break;
+
+       case SKL_D0I3_NON_STREAMING:
+               d0i3->non_streaming++;
+               break;
+       }
+}
+
+void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps)
+{
+       struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
+
+       switch (caps) {
+       case SKL_D0I3_NONE:
+               d0i3->non_d0i3--;
+               break;
+
+       case SKL_D0I3_STREAMING:
+               d0i3->streaming--;
+               break;
+
+       case SKL_D0I3_NON_STREAMING:
+               d0i3->non_streaming--;
+               break;
+       }
+}
+
 /*
  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
  * ignore. This helpers checks if the SKL driver handles this widget type
@@ -1519,6 +1557,10 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev,
                pipe->memory_pages = tkn_val;
                break;
 
+       case SKL_TKN_U32_PMODE:
+               pipe->lp_mode = tkn_val;
+               break;
+
        default:
                dev_err(dev, "Token not handled %d\n", tkn);
                return -EINVAL;
@@ -1826,6 +1868,10 @@ static int skl_tplg_get_token(struct device *dev,
                mconfig->converter = tkn_elem->value;
                break;
 
+       case SKL_TKL_U32_D0I3_CAPS:
+               mconfig->d0i3_caps = tkn_elem->value;
+               break;
+
        case SKL_TKN_U32_PIPE_ID:
                ret = skl_tplg_add_pipe(dev,
                                mconfig, skl, tkn_elem);
@@ -1841,6 +1887,7 @@ static int skl_tplg_get_token(struct device *dev,
        case SKL_TKN_U32_PIPE_CONN_TYPE:
        case SKL_TKN_U32_PIPE_PRIORITY:
        case SKL_TKN_U32_PIPE_MEM_PGS:
+       case SKL_TKN_U32_PMODE:
                if (is_pipe_exists) {
                        ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
                                        tkn_elem->token, tkn_elem->value);
index a519360f42a62d42b2c7a39b9ab8e0dac19bc28d..08d39280b07bcd09bd3a62c7de4f99ba7290add3 100644 (file)
@@ -113,23 +113,6 @@ struct skl_cpr_gtw_cfg {
        u32 config_data[1];
 } __packed;
 
-struct skl_i2s_config_blob {
-       u32 gateway_attrib;
-       u32 tdm_ts_group[8];
-       u32 ssc0;
-       u32 ssc1;
-       u32 sscto;
-       u32 sspsp;
-       u32 sstsa;
-       u32 ssrsa;
-       u32 ssc2;
-       u32 sspsp2;
-       u32 ssc3;
-       u32 ssioc;
-       u32 mdivc;
-       u32 mdivr;
-} __packed;
-
 struct skl_dma_control {
        u32 node_id;
        u32 config_length;
@@ -279,6 +262,7 @@ struct skl_pipe {
        u8 pipe_priority;
        u16 conn_type;
        u32 memory_pages;
+       u8 lp_mode;
        struct skl_pipe_params *p_params;
        enum skl_pipe_state state;
        struct list_head w_list;
@@ -293,6 +277,12 @@ enum skl_module_state {
        SKL_MODULE_UNLOADED = 4,
 };
 
+enum d0i3_capability {
+       SKL_D0I3_NONE = 0,
+       SKL_D0I3_STREAMING = 1,
+       SKL_D0I3_NON_STREAMING = 2,
+};
+
 struct skl_module_cfg {
        u8 guid[16];
        struct skl_module_inst_id id;
@@ -319,6 +309,7 @@ struct skl_module_cfg {
        u32 converter;
        u32 vbus_id;
        u32 mem_pages;
+       enum d0i3_capability d0i3_caps;
        struct skl_module_pin *m_in_pin;
        struct skl_module_pin *m_out_pin;
        enum skl_module_type m_type;
@@ -361,6 +352,9 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module(
 int skl_tplg_update_pipe_params(struct device *dev,
                struct skl_module_cfg *mconfig, struct skl_pipe_params *params);
 
+void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps);
+void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps);
+
 int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe);
 
 int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
index 2989c164dafe3a719ed219d2f47ddf73a20ea64d..da5db509827429d060cd429ea0c93b9f984fa6e4 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
+#include <linux/delay.h>
 #include <sound/pcm.h>
 #include "../common/sst-acpi.h"
 #include <sound/hda_register.h>
@@ -109,6 +110,52 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
        return ret;
 }
 
+void skl_update_d0i3c(struct device *dev, bool enable)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+       struct hdac_bus *bus = ebus_to_hbus(ebus);
+       u8 reg;
+       int timeout = 50;
+
+       reg = snd_hdac_chip_readb(bus, VS_D0I3C);
+       /* Do not write to D0I3C until command in progress bit is cleared */
+       while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) {
+               udelay(10);
+               reg = snd_hdac_chip_readb(bus, VS_D0I3C);
+       }
+
+       /* Highly unlikely. But if it happens, flag error explicitly */
+       if (!timeout) {
+               dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n");
+               return;
+       }
+
+       if (enable)
+               reg = reg | AZX_REG_VS_D0I3C_I3;
+       else
+               reg = reg & (~AZX_REG_VS_D0I3C_I3);
+
+       snd_hdac_chip_writeb(bus, VS_D0I3C, reg);
+
+       timeout = 50;
+       /* Wait for cmd in progress to be cleared before exiting the function */
+       reg = snd_hdac_chip_readb(bus, VS_D0I3C);
+       while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) {
+               udelay(10);
+               reg = snd_hdac_chip_readb(bus, VS_D0I3C);
+       }
+
+       /* Highly unlikely. But if it happens, flag error explicitly */
+       if (!timeout) {
+               dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n");
+               return;
+       }
+
+       dev_dbg(bus->dev, "D0I3C register = 0x%x\n",
+                       snd_hdac_chip_readb(bus, VS_D0I3C));
+}
+
 /* called from IRQ */
 static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
 {
@@ -181,6 +228,15 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
        return 0;
 }
 
+static int skl_suspend_late(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+       struct skl *skl = ebus_to_skl(ebus);
+
+       return skl_suspend_late_dsp(skl);
+}
+
 #ifdef CONFIG_PM
 static int _skl_suspend(struct hdac_ext_bus *ebus)
 {
@@ -243,7 +299,6 @@ static int skl_suspend(struct device *dev)
 
                enable_irq_wake(bus->irq);
                pci_save_state(pci);
-               pci_disable_device(pci);
        } else {
                ret = _skl_suspend(ebus);
                if (ret < 0)
@@ -286,7 +341,6 @@ static int skl_resume(struct device *dev)
         */
        if (skl->supend_active) {
                pci_restore_state(pci);
-               ret = pci_enable_device(pci);
                snd_hdac_ext_bus_link_power_up_all(ebus);
                disable_irq_wake(bus->irq);
                /*
@@ -345,6 +399,7 @@ static int skl_runtime_resume(struct device *dev)
 static const struct dev_pm_ops skl_pm = {
        SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume)
        SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL)
+       .suspend_late = skl_suspend_late,
 };
 
 /*
@@ -674,7 +729,7 @@ static int skl_probe(struct pci_dev *pci,
 
        if (skl->nhlt == NULL) {
                err = -ENODEV;
-               goto out_free;
+               goto out_display_power_off;
        }
 
        skl_nhlt_update_topology_bin(skl);
@@ -746,6 +801,9 @@ out_mach_free:
        skl_machine_device_unregister(skl);
 out_nhlt_free:
        skl_nhlt_free(skl->nhlt);
+out_display_power_off:
+       if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+               snd_hdac_display_power(bus, false);
 out_free:
        skl->init_failed = 1;
        skl_free(ebus);
@@ -785,8 +843,7 @@ static void skl_remove(struct pci_dev *pci)
 
        release_firmware(skl->tplg);
 
-       if (pci_dev_run_wake(pci))
-               pm_runtime_get_noresume(&pci->dev);
+       pm_runtime_get_noresume(&pci->dev);
 
        /* codec removal, invoke bus_device_remove */
        snd_hdac_ext_bus_device_remove(ebus);
index 5d4fbb094c48da9fe238b8c27f09f3c41141d0ed..4986e3929dd3a77f4ed637a6fec130f1b5efb555 100644 (file)
@@ -52,6 +52,9 @@
 #define AZX_PGCTL_LSRMD_MASK           (1 << 4)
 #define AZX_PCIREG_CGCTL               0x48
 #define AZX_CGCTL_MISCBDCGE_MASK       (1 << 6)
+/* D0I3C Register fields */
+#define AZX_REG_VS_D0I3C_CIP      0x1 /* Command in progress */
+#define AZX_REG_VS_D0I3C_I3       0x4 /* D0i3 enable */
 
 struct skl_dsp_resource {
        u32 max_mcps;
@@ -121,8 +124,11 @@ int skl_get_dmic_geo(struct skl *skl);
 int skl_nhlt_update_topology_bin(struct skl *skl);
 int skl_init_dsp(struct skl *skl);
 int skl_free_dsp(struct skl *skl);
+int skl_suspend_late_dsp(struct skl *skl);
 int skl_suspend_dsp(struct skl *skl);
 int skl_resume_dsp(struct skl *skl);
 void skl_cleanup_resources(struct skl *skl);
 const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
+void skl_update_d0i3c(struct device *dev, bool enable);
+
 #endif /* __SOUND_SOC_SKL_H */
index e0304d544f26ba45660e94fa98942d2416ddb94a..677a48d7b89199d9719fcf27dc8482f56100190f 100644 (file)
@@ -42,7 +42,7 @@ static int a370db_hw_params(struct snd_pcm_substream *substream,
        return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
 }
 
-static struct snd_soc_ops a370db_ops = {
+static const struct snd_soc_ops a370db_ops = {
        .hw_params = a370db_hw_params,
 };
 
index 13631003cb7c6796d49f5278834eb5924aea294c..a002ab892772106bae79532d4836814411eaef2f 100644 (file)
@@ -735,6 +735,11 @@ static int mxs_saif_probe(struct platform_device *pdev)
        else
                saif->id = ret;
 
+       if (saif->id >= ARRAY_SIZE(mxs_saif)) {
+               dev_err(&pdev->dev, "get wrong saif id\n");
+               return -EINVAL;
+       }
+
        /*
         * If there is no "fsl,saif-master" phandle, it's a saif
         * master.  Otherwise, it's a slave and its phandle points
@@ -749,11 +754,11 @@ static int mxs_saif_probe(struct platform_device *pdev)
                        return ret;
                else
                        saif->master_id = ret;
-       }
 
-       if (saif->master_id >= ARRAY_SIZE(mxs_saif)) {
-               dev_err(&pdev->dev, "get wrong master id\n");
-               return -EINVAL;
+               if (saif->master_id >= ARRAY_SIZE(mxs_saif)) {
+                       dev_err(&pdev->dev, "get wrong master id\n");
+                       return -EINVAL;
+               }
        }
 
        mxs_saif[saif->id] = saif;
index 2b23ffbac6b126cdff2674f68133dea77c40f546..a96276e773328b39b0feb1d6d603b77a672d2048 100644 (file)
@@ -68,7 +68,7 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
+static const struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
        .hw_params = mxs_sgtl5000_hw_params,
 };
 
index f2bf8661dd21f782b1d472a724d69902a56b7b57..823b5a236d8dce0943d160a6cd436df2865a76e6 100644 (file)
@@ -208,7 +208,7 @@ config SND_PXA2XX_SOC_IMOTE2
 
 config SND_MMP_SOC_BROWNSTONE
        tristate "SoC Audio support for Marvell Brownstone"
-       depends on SND_MMP_SOC && MACH_BROWNSTONE
+       depends on SND_MMP_SOC && MACH_BROWNSTONE && I2C
        select SND_MMP_SOC_SSPA
        select MFD_WM8994
        select SND_SOC_WM8994
index dcbb7aa9830c0347af6f7bd2c198639e52d9e24e..311774e9ca469197e1aec91523ecbb8e9135ee0f 100644 (file)
@@ -244,9 +244,9 @@ static const struct snd_soc_dapm_route corgi_audio_map[] = {
        {"MICIN", NULL, "Line Jack"},
 };
 
-static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
-       "Off"};
-static const char *spk_function[] = {"On", "Off"};
+static const char * const jack_function[] = {"Headphone", "Mic", "Line",
+       "Headset", "Off"};
+static const char * const spk_function[] = {"On", "Off"};
 static const struct soc_enum corgi_enum[] = {
        SOC_ENUM_SINGLE_EXT(5, jack_function),
        SOC_ENUM_SINGLE_EXT(2, spk_function),
index ecbf2873b7ffd8e205ce86fdd7dfa743ebe9435c..85483049b916db5fef5fee39b97e4fb7fbcc71e8 100644 (file)
@@ -27,8 +27,6 @@
 #include <asm/mach-types.h>
 #include "pxa2xx-i2s.h"
 
-#include "../codecs/ak4641.h"
-
 static struct snd_soc_jack hs_jack;
 
 /* Headphones jack detection DAPM pin */
index 62b8377a9d2b93c81f06a8df4c0b5ed2cd7a567f..2d4d4455fe8769a0eee091fd1bdc2cd3cdc711fe 100644 (file)
@@ -376,7 +376,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"VINM", NULL, "Call Mic"},
 };
 
-static const char *input_select[] = {"Call Mic", "Headset Mic"};
+static const char * const input_select[] = {"Call Mic", "Headset Mic"};
 static const struct soc_enum magician_in_sel_enum =
        SOC_ENUM_SINGLE_EXT(2, input_select);
 
index d1661fa6ee0818a037c66524bd3f88b8e3be8d2e..0fe0abec8fc4cf3db262919264133555e665dcdb 100644 (file)
@@ -187,7 +187,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
        mioa701.dev = &pdev->dev;
        rc = devm_snd_soc_register_card(&pdev->dev, &mioa701);
        if (!rc)
-               dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will"
+               dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will "
                         "lead to overheating and possible destruction of your device."
                         " Do not use without a good knowledge of mio's board design!\n");
        return rc;
index 4b3b714f5ee7a67e5538b191a9da99bac86e56f8..a879aba0691fe7d20f2e6be6e39c08a632c20dd4 100644 (file)
@@ -209,8 +209,8 @@ static const struct snd_soc_dapm_route poodle_audio_map[] = {
        {"MICIN", NULL, "Microphone"},
 };
 
-static const char *jack_function[] = {"Off", "Headphone"};
-static const char *spk_function[] = {"Off", "On"};
+static const char * const jack_function[] = {"Off", "Headphone"};
+static const char * const spk_function[] = {"Off", "On"};
 static const struct soc_enum poodle_enum[] = {
        SOC_ENUM_SINGLE_EXT(2, jack_function),
        SOC_ENUM_SINGLE_EXT(2, spk_function),
index bc79da221c0df018942b80c613be5d8d11ef6bf9..abf6ec080258d17721f301558129dfb1688bdecc 100644 (file)
@@ -9,12 +9,6 @@
 #ifndef _PXA_SSP_H
 #define _PXA_SSP_H
 
-/* pxa DAI SSP IDs */
-#define PXA_DAI_SSP1                   0
-#define PXA_DAI_SSP2                   1
-#define PXA_DAI_SSP3                   2
-#define PXA_DAI_SSP4                   3
-
 /* SSP clock sources */
 #define PXA_SSP_CLK_PLL        0
 #define PXA_SSP_CLK_EXT        1
index 070f3c6059fed6e880f8cce055731506b43c71e8..7e218e2105a98f3e5f0d4beda90012bd3f94b257 100644 (file)
@@ -9,9 +9,6 @@
 #ifndef _PXA2XX_I2S_H
 #define _PXA2XX_I2S_H
 
-/* pxa2xx DAI ID's */
-#define PXA2XX_DAI_I2S                 0
-
 /* I2S clock */
 #define PXA2XX_I2S_SYSCLK              0
 
index 0e02634c8b7f6f41764b75344ae850ff7ce586d7..07d77cddac601be5b53e7801f516667e19c806a7 100644 (file)
@@ -241,9 +241,9 @@ static const struct snd_soc_dapm_route spitz_audio_map[] = {
        {"LINPUT1", NULL, "Line Jack"},
 };
 
-static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
-       "Off"};
-static const char *spk_function[] = {"On", "Off"};
+static const char * const jack_function[] = {"Headphone", "Mic", "Line",
+       "Headset", "Off"};
+static const char * const spk_function[] = {"On", "Off"};
 static const struct soc_enum spitz_enum[] = {
        SOC_ENUM_SINGLE_EXT(5, jack_function),
        SOC_ENUM_SINGLE_EXT(2, spk_function),
index c508f024ecfbc206887aeb9f91943311a279aed7..08b0cf50e91a05a077a7ceba5d01d985ef3285ea 100644 (file)
@@ -170,9 +170,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Mic Bias", NULL, "Headset Jack"},
 };
 
-static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
-       "Off"};
-static const char *spk_function[] = {"On", "Off"};
+static const char * const jack_function[] = {"Headphone", "Mic", "Line",
+       "Headset", "Off"};
+static const char * const spk_function[] = {"On", "Off"};
 static const struct soc_enum tosa_enum[] = {
        SOC_ENUM_SINGLE_EXT(5, jack_function),
        SOC_ENUM_SINGLE_EXT(2, spk_function),
index 07f91e918b2349b75271ac319f85e6416a4199e6..d084d746829988f5e76c3131e894e3e74e1ff786 100644 (file)
@@ -123,20 +123,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
                        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) {
+               ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
+
+               if (ret < 0) {
                        dev_err(card->dev, "error getting codec dai name\n");
                        return ERR_PTR(ret);
                }
index 3cde9fb977fa72779a2ff26530fbaafae29a6386..eff3f9a8b685fc2ff0a149c4f3f7cf3101a984af 100644 (file)
@@ -586,3 +586,6 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
        return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
+
+MODULE_DESCRIPTION("QTi LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
index e2ff538a8aa5b63c4117f35365c39057b1f5360a..dd5bdd0da73048c627417c45980dde5032043656 100644 (file)
@@ -25,8 +25,7 @@
 #include "lpass.h"
 
 struct lpass_pcm_data {
-       int rdma_ch;
-       int wrdma_ch;
+       int dma_ch;
        int i2s_port;
 };
 
@@ -61,7 +60,41 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       int ret;
+       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, dma_ch, dir = substream->stream;
+       struct lpass_pcm_data *data;
+
+       data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->i2s_port = cpu_dai->driver->id;
+       runtime->private_data = data;
+
+       dma_ch = 0;
+       if (v->alloc_dma_channel)
+               dma_ch = v->alloc_dma_channel(drvdata, dir);
+       else
+               dma_ch = 0;
+
+       if (dma_ch < 0)
+               return dma_ch;
+
+       drvdata->substream[dma_ch] = substream;
+
+       ret = regmap_write(drvdata->lpaif_map,
+                       LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
+       if (ret) {
+               dev_err(soc_runtime->dev,
+                       "%s() error writing to rdmactl reg: %d\n",
+                       __func__, ret);
+                       return ret;
+       }
+
+       data->dma_ch = dma_ch;
 
        snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
 
@@ -80,13 +113,32 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+       struct lpass_data *drvdata =
+               snd_soc_platform_get_drvdata(soc_runtime->platform);
+       struct lpass_variant *v = drvdata->variant;
+       struct lpass_pcm_data *data;
+
+       data = runtime->private_data;
+       v = drvdata->variant;
+       drvdata->substream[data->dma_ch] = NULL;
+       if (v->free_dma_channel)
+               v->free_dma_channel(drvdata, data->dma_ch);
+
+       return 0;
+}
+
 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_data *drvdata =
                snd_soc_platform_get_drvdata(soc_runtime->platform);
-       struct lpass_pcm_data *pcm_data = drvdata->private_data;
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        snd_pcm_format_t format = params_format(params);
        unsigned int channels = params_channels(params);
@@ -95,10 +147,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
        int bitwidth;
        int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
 
-       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK)
-               ch = pcm_data->rdma_ch;
-       else
-               ch = pcm_data->wrdma_ch;
+       ch = pcm_data->dma_ch;
 
        bitwidth = snd_pcm_format_width(format);
        if (bitwidth < 0) {
@@ -179,16 +228,13 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *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 *pcm_data = drvdata->private_data;
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        unsigned int reg;
        int ret;
 
-       if (substream->stream ==  SNDRV_PCM_STREAM_PLAYBACK)
-               reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch);
-       else
-               reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch);
-
+       reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream);
        ret = regmap_write(drvdata->lpaif_map, reg, 0);
        if (ret)
                dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -203,14 +249,12 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *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 *pcm_data = drvdata->private_data;
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        int ret, ch, dir = substream->stream;
 
-       if (dir ==  SNDRV_PCM_STREAM_PLAYBACK)
-               ch = pcm_data->rdma_ch;
-       else
-               ch = pcm_data->wrdma_ch;
+       ch = pcm_data->dma_ch;
 
        ret = regmap_write(drvdata->lpaif_map,
                        LPAIF_DMABASE_REG(v, ch, dir),
@@ -257,14 +301,12 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *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 *pcm_data = drvdata->private_data;
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        int ret, ch, dir = substream->stream;
 
-       if (dir == SNDRV_PCM_STREAM_PLAYBACK)
-               ch = pcm_data->rdma_ch;
-       else
-               ch = pcm_data->wrdma_ch;
+       ch = pcm_data->dma_ch;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -333,15 +375,13 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
        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 *pcm_data = drvdata->private_data;
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct lpass_pcm_data *pcm_data = rt->private_data;
        struct lpass_variant *v = drvdata->variant;
        unsigned int base_addr, curr_addr;
        int ret, ch, dir = substream->stream;
 
-       if (dir == SNDRV_PCM_STREAM_PLAYBACK)
-               ch = pcm_data->rdma_ch;
-       else
-               ch = pcm_data->wrdma_ch;
+       ch = pcm_data->dma_ch;
 
        ret = regmap_read(drvdata->lpaif_map,
                        LPAIF_DMABASE_REG(v, ch, dir), &base_addr);
@@ -374,6 +414,7 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
 
 static const struct snd_pcm_ops lpass_platform_pcm_ops = {
        .open           = lpass_platform_pcmops_open,
+       .close          = lpass_platform_pcmops_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = lpass_platform_pcmops_hw_params,
        .hw_free        = lpass_platform_pcmops_hw_free,
@@ -470,117 +511,45 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 {
        struct snd_pcm *pcm = soc_runtime->pcm;
        struct snd_pcm_substream *psubstream, *csubstream;
-       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 = -EINVAL;
-       struct lpass_pcm_data *data;
        size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 
-       data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       data->i2s_port = cpu_dai->driver->id;
-       drvdata->private_data = data;
-
        psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
        if (psubstream) {
-               if (v->alloc_dma_channel)
-                       data->rdma_ch = v->alloc_dma_channel(drvdata,
-                                               SNDRV_PCM_STREAM_PLAYBACK);
-
-               if (data->rdma_ch < 0)
-                       return data->rdma_ch;
-
-               drvdata->substream[data->rdma_ch] = psubstream;
-
                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
                                        soc_runtime->platform->dev,
                                        size, &psubstream->dma_buffer);
-               if (ret)
-                       goto playback_alloc_err;
-
-               ret = regmap_write(drvdata->lpaif_map,
-                       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);
-                       goto capture_alloc_err;
+                       dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
+                       return ret;
                }
        }
 
        csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
        if (csubstream) {
-               if (v->alloc_dma_channel)
-                       data->wrdma_ch = v->alloc_dma_channel(drvdata,
-                                               SNDRV_PCM_STREAM_CAPTURE);
-
-               if (data->wrdma_ch < 0) {
-                       ret = data->wrdma_ch;
-                       goto capture_alloc_err;
-               }
-
-               drvdata->substream[data->wrdma_ch] = csubstream;
-
                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
                                        soc_runtime->platform->dev,
                                        size, &csubstream->dma_buffer);
-               if (ret)
-                       goto capture_alloc_err;
-
-               ret = regmap_write(drvdata->lpaif_map,
-                       LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0);
                if (ret) {
-                       dev_err(soc_runtime->dev,
-                               "%s() error writing to wrdmactl reg: %d\n",
-                               __func__, ret);
-                       goto capture_reg_err;
+                       dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
+                       if (psubstream)
+                               snd_dma_free_pages(&psubstream->dma_buffer);
+                       return ret;
                }
+
        }
 
        return 0;
-
-capture_reg_err:
-       if (csubstream)
-               snd_dma_free_pages(&csubstream->dma_buffer);
-
-capture_alloc_err:
-       if (psubstream)
-               snd_dma_free_pages(&psubstream->dma_buffer);
-
- playback_alloc_err:
-       dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
-
-       return ret;
 }
 
 static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 {
-       struct snd_soc_pcm_runtime *rt;
-       struct lpass_data *drvdata;
-       struct lpass_pcm_data *data;
-       struct lpass_variant *v;
        struct snd_pcm_substream *substream;
-       int ch, i;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
                substream = pcm->streams[i].substream;
                if (substream) {
-                       rt = substream->private_data;
-                       drvdata = snd_soc_platform_get_drvdata(rt->platform);
-                       data = drvdata->private_data;
-
-                       ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                               ? data->rdma_ch
-                               : data->wrdma_ch;
-                       v = drvdata->variant;
-                       drvdata->substream[ch] = NULL;
-                       if (v->free_dma_channel)
-                               v->free_dma_channel(drvdata, ch);
-
                        snd_dma_free_pages(&substream->dma_buffer);
                        substream->dma_buffer.area = NULL;
                        substream->dma_buffer.addr = 0;
index 35b3cea8207d8e61773a938d7fead9b3adb8d087..924971b6ded54f52ef56de0c84910258531bf1b9 100644 (file)
@@ -59,7 +59,6 @@ struct lpass_data {
        struct clk *pcnoc_mport_clk;
        struct clk *pcnoc_sway_clk;
 
-       void *private_data;
 };
 
 /* Vairant data per each SOC */
index 2d833bffdba0340142f4fb3bc63da9851df90ff3..8fcac2ac3aa6adb6d61388a86bf57544aadff12b 100644 (file)
@@ -58,7 +58,7 @@ static int storm_ops_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_ops storm_soc_ops = {
+static const struct snd_soc_ops storm_soc_ops = {
        .hw_params      = storm_ops_hw_params,
 };
 
index 9ed735a6cf49ac352d237850423a276ed926ffd4..3475c61a5fa0bf76f989bd21bf43815b75aef627 100644 (file)
@@ -38,7 +38,7 @@
 
 #define SOUND_FS       256
 
-unsigned int rt5514_dmic_delay;
+static unsigned int rt5514_dmic_delay;
 
 static struct snd_soc_jack rockchip_sound_jack;
 
@@ -228,15 +228,15 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-static struct snd_soc_ops rockchip_sound_max98357a_ops = {
+static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
        .hw_params = rockchip_sound_max98357a_hw_params,
 };
 
-static struct snd_soc_ops rockchip_sound_rt5514_ops = {
+static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
        .hw_params = rockchip_sound_rt5514_hw_params,
 };
 
-static struct snd_soc_ops rockchip_sound_da7219_ops = {
+static const struct snd_soc_ops rockchip_sound_da7219_ops = {
        .hw_params = rockchip_sound_da7219_hw_params,
 };
 
index e70ffad07184fafa3584c2f7ee18a883baa386fb..789d6f1e2b5fcb97b444f0d7e4c737fa174ed312 100644 (file)
@@ -119,7 +119,7 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_ops rk_aif1_ops = {
+static const struct snd_soc_ops rk_aif1_ops = {
        .hw_params = rk_aif1_hw_params,
 };
 
index 440a8026346a3ed4004ed744f9600049c1c82a12..9e0c178058074e5102b73978c9c15082e2be9f72 100644 (file)
@@ -135,7 +135,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
                                     &headset_jack);
 }
 
-static struct snd_soc_ops rk_aif1_ops = {
+static const struct snd_soc_ops rk_aif1_ops = {
        .hw_params = rk_aif1_hw_params,
 };
 
index 97d6700b100935466d01f5afad0a3c1fed54a931..cbc0023c2bc8276da9cda23ffa4d570d7c03e09f 100644 (file)
@@ -383,11 +383,6 @@ static int s3c_ac97_probe(struct platform_device *pdev)
                goto err4;
        }
 
-       ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
-                                        s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
-       if (ret)
-               goto err5;
-
        ret = samsung_asoc_dma_platform_register(&pdev->dev,
                                                 ac97_pdata->dma_filter,
                                                 NULL, NULL);
@@ -396,6 +391,11 @@ static int s3c_ac97_probe(struct platform_device *pdev)
                goto err5;
        }
 
+       ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
+                                        s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+       if (ret)
+               goto err5;
+
        return 0;
 err5:
        free_irq(irq_res->start, NULL);
index 9104c98deeb75ab8ac3113e5be85ff4958fa2bdf..cda656e4afc6985e0fe6ffb78f3abe486d7374e2 100644 (file)
@@ -37,12 +37,8 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter,
        pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config;
        pcm_conf->compat_filter_fn = filter;
 
-       if (dev->of_node) {
-               pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx;
-               pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx;
-       } else {
-               flags |= SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME;
-       }
+       pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx;
+       pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx;
 
        return devm_snd_dmaengine_pcm_register(dev, pcm_conf, flags);
 }
index 7e32cf4581f8a853a2e53bf49cbb84e1bd11f0b8..8766ebb0dc9b750b49f1ad1c5b6abca60e5f8e4f 100644 (file)
@@ -1237,14 +1237,14 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "Unable to get drvdata\n");
                        return -EFAULT;
                }
-               ret = devm_snd_soc_register_component(&sec_dai->pdev->dev,
-                                               &samsung_i2s_component,
-                                               &sec_dai->i2s_dai_drv, 1);
+               ret = samsung_asoc_dma_platform_register(&pdev->dev,
+                                       sec_dai->filter, "tx-sec", NULL);
                if (ret != 0)
                        return ret;
 
-               return samsung_asoc_dma_platform_register(&pdev->dev,
-                                       sec_dai->filter, "tx-sec", NULL);
+               return devm_snd_soc_register_component(&sec_dai->pdev->dev,
+                                               &samsung_i2s_component,
+                                               &sec_dai->i2s_dai_drv, 1);
        }
 
        pri_dai = i2s_alloc_dai(pdev, false);
@@ -1304,8 +1304,6 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        }
        pri_dai->dma_playback.addr = regs_base + I2STXD;
        pri_dai->dma_capture.addr = regs_base + I2SRXD;
-       pri_dai->dma_playback.chan_name = "tx";
-       pri_dai->dma_capture.chan_name = "rx";
        pri_dai->dma_playback.addr_width = 4;
        pri_dai->dma_capture.addr_width = 4;
        pri_dai->quirks = quirks;
@@ -1314,6 +1312,11 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        if (quirks & QUIRK_PRI_6CHAN)
                pri_dai->i2s_dai_drv.playback.channels_max = 6;
 
+       ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter,
+                                                NULL, NULL);
+       if (ret < 0)
+               goto err_disable_clk;
+
        if (quirks & QUIRK_SEC_DAI) {
                sec_dai = i2s_alloc_dai(pdev, true);
                if (!sec_dai) {
@@ -1325,7 +1328,6 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                sec_dai->lock = &pri_dai->spinlock;
                sec_dai->variant_regs = pri_dai->variant_regs;
                sec_dai->dma_playback.addr = regs_base + I2STXDS;
-               sec_dai->dma_playback.chan_name = "tx-sec";
 
                if (!np) {
                        sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec;
@@ -1353,10 +1355,6 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_free_dai;
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter,
-                                                NULL, NULL);
-       if (ret < 0)
-               goto err_free_dai;
 
        pm_runtime_enable(&pdev->dev);
 
index 43e367a9acc368d148c0a5afbe777c2874f2ea30..c484985812ed681fa5a4326f3c54f76e4a80da4b 100644 (file)
@@ -565,24 +565,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
        pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
        pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
 
+       ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
+                                                NULL, NULL);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
+               goto err5;
+       }
+
        pm_runtime_enable(&pdev->dev);
 
        ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
                                         &s3c_pcm_dai[pdev->id], 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
-               goto err5;
-       }
-
-       ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
-                                                NULL, NULL);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
-               goto err5;
+               goto err6;
        }
 
        return 0;
-
+err6:
+       pm_runtime_disable(&pdev->dev);
 err5:
        clk_disable_unprepare(pcm->pclk);
 err4:
index 3e89fbc0c51d046049f6b6413d554c7e62186055..6d0b8897fa6cdf64e77aec7c951234a2e285d89d 100644 (file)
 #include <linux/platform_data/asoc-s3c.h>
 
 static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = {
-       .chan_name      = "tx",
        .addr_width     = 4,
 };
 
 static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = {
-       .chan_name      = "rx",
        .addr_width     = 4,
 };
 
@@ -168,19 +166,19 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
        s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD;
        s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
 
-       ret = s3c_i2sv2_register_component(&pdev->dev, -1,
-                                          &s3c2412_i2s_component,
-                                          &s3c2412_i2s_dai);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev,
+                                                pdata->dma_filter,
+                                                NULL, NULL);
        if (ret) {
-               pr_err("failed to register the dai\n");
+               pr_err("failed to register the DMA: %d\n", ret);
                return ret;
        }
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev,
-                                                pdata->dma_filter,
-                                                NULL, NULL);
+       ret = s3c_i2sv2_register_component(&pdev->dev, -1,
+                                          &s3c2412_i2s_component,
+                                          &s3c2412_i2s_dai);
        if (ret)
-               pr_err("failed to register the DMA: %d\n", ret);
+               pr_err("failed to register the dai\n");
 
        return ret;
 }
index c78a936a30995639fdb6cf6c97008d7504b1ea5e..1898277602293deaa1f49b39dd34e6c0863352a9 100644 (file)
 #include <linux/platform_data/asoc-s3c.h>
 
 static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = {
-       .chan_name      = "tx",
        .addr_width     = 2,
 };
 
 static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = {
-       .chan_name      = "rx",
        .addr_width     = 2,
 };
 
@@ -474,18 +472,18 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
        s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO;
        s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
 
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                       &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev,
+                                                pdata->dma_filter,
+                                                NULL, NULL);
        if (ret) {
-               pr_err("failed to register the dai\n");
+               pr_err("failed to register the dma: %d\n", ret);
                return ret;
        }
 
-       ret = samsung_asoc_dma_platform_register(&pdev->dev,
-                                                pdata->dma_filter,
-                                                NULL, NULL);
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                       &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1);
        if (ret)
-               pr_err("failed to register the dma: %d\n", ret);
+               pr_err("failed to register the dai\n");
 
        return ret;
 }
index 26c1fbed4d3543da990ea3277a24f8fb87887818..779504f54bc074fcaec0ce179483b3a4a1bc17ee 100644 (file)
@@ -416,15 +416,6 @@ static int spdif_probe(struct platform_device *pdev)
                goto err3;
        }
 
-       dev_set_drvdata(&pdev->dev, spdif);
-
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                       &samsung_spdif_component, &samsung_spdif_dai, 1);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "fail to register dai\n");
-               goto err4;
-       }
-
        spdif_stereo_out.addr_width = 2;
        spdif_stereo_out.addr = mem_res->start + DATA_OUTBUF;
        filter = NULL;
@@ -432,7 +423,6 @@ static int spdif_probe(struct platform_device *pdev)
                spdif_stereo_out.filter_data = spdif_pdata->dma_playback;
                filter = spdif_pdata->dma_filter;
        }
-
        spdif->dma_playback = &spdif_stereo_out;
 
        ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
@@ -442,6 +432,15 @@ static int spdif_probe(struct platform_device *pdev)
                goto err4;
        }
 
+       dev_set_drvdata(&pdev->dev, spdif);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                       &samsung_spdif_component, &samsung_spdif_dai, 1);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "fail to register dai\n");
+               goto err4;
+       }
+
        return 0;
 err4:
        iounmap(spdif->regs);
index 6db6405d952f87c9b742ae833ea2735f9925e9db..147ebecfed9438068cb4c65560e937a34dbbe065 100644 (file)
@@ -1,5 +1,5 @@
 menu "SoC Audio support for SuperH"
-       depends on SUPERH || ARCH_SHMOBILE
+       depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
 
 config SND_SOC_PCM_SH7760
        tristate "SoC Audio support for Renesas SH7760"
@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU
 config SND_SOC_RCAR
        tristate "R-Car series SRU/SCU/SSIU/SSI support"
        depends on COMMON_CLK
+       depends on OF || COMPILE_TEST
        select SND_SIMPLE_CARD
        select REGMAP_MMIO
        help
index 2145957d02290f4e61b97fdf01b01b4716b7f0b6..85a33ac0a5c443f86159480d9c74d02711cb0c8b 100644 (file)
@@ -34,6 +34,9 @@ struct rsnd_adg {
        struct clk_onecell_data onecell;
        struct rsnd_mod mod;
        u32 flags;
+       u32 ckr;
+       u32 rbga;
+       u32 rbgb;
 
        int rbga_rate_for_441khz; /* RBGA */
        int rbgb_rate_for_48khz;  /* RBGB */
@@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
        struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
        struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
        struct clk *clk;
        int i;
        u32 data;
+       u32 ckr = 0;
        int sel_table[] = {
                [CLKA] = 0x1,
                [CLKB] = 0x2,
@@ -360,15 +365,14 @@ found_clock:
        rsnd_adg_set_ssi_clk(ssi_mod, data);
 
        if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) {
-               struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-               u32 ckr = 0;
-
                if (0 == (rate % 8000))
                        ckr = 0x80000000;
-
-               rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr);
        }
 
+       rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr);
+       rsnd_mod_write(adg_mod, BRRA,  adg->rbga);
+       rsnd_mod_write(adg_mod, BRRB,  adg->rbgb);
+
        dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
                rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
                data, rate);
@@ -376,6 +380,25 @@ found_clock:
        return 0;
 }
 
+void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
+{
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       int i, ret;
+
+       for_each_rsnd_clk(clk, adg, i) {
+               ret = 0;
+               if (enable)
+                       ret = clk_prepare_enable(clk);
+               else
+                       clk_disable_unprepare(clk);
+
+               if (ret < 0)
+                       dev_warn(dev, "can't use clk %d\n", i);
+       }
+}
+
 static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
                               struct rsnd_adg *adg)
 {
@@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
                [CLKC]  = "clk_c",
                [CLKI]  = "clk_i",
        };
-       int i, ret;
+       int i;
 
        for (i = 0; i < CLKMAX; i++) {
                clk = devm_clk_get(dev, clk_name[i]);
                adg->clk[i] = IS_ERR(clk) ? NULL : clk;
        }
 
-       for_each_rsnd_clk(clk, adg, i) {
-               ret = clk_prepare_enable(clk);
-               if (ret < 0)
-                       dev_warn(dev, "can't use clk %d\n", i);
-
+       for_each_rsnd_clk(clk, adg, i)
                dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
-       }
 }
 
 static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
                                struct rsnd_adg *adg)
 {
        struct clk *clk;
-       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct device_node *np = dev->of_node;
        u32 ckr, rbgx, rbga, rbgb;
@@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
                }
        }
 
-       rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr);
-       rsnd_mod_write(adg_mod, BRRA,  rbga);
-       rsnd_mod_write(adg_mod, BRRB,  rbgb);
+       adg->ckr = ckr;
+       adg->rbga = rbga;
+       adg->rbgb = rbgb;
 
        for_each_rsnd_clkout(clk, adg, i)
                dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
-       dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
+       dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
                ckr, rbga, rbgb);
 }
 
@@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
 
        priv->adg = adg;
 
+       rsnd_adg_clk_enable(priv);
+
        return 0;
 }
 
 void rsnd_adg_remove(struct rsnd_priv *priv)
 {
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct clk *clk;
-       int i;
-
-       for_each_rsnd_clk(clk, adg, i) {
-               clk_disable_unprepare(clk);
-       }
+       rsnd_adg_clk_disable(priv);
 }
index f18141098b50184231bc7a12b8fa41f881435740..4bd68de761309b57285bf203aa2ee46cabc440cc 100644 (file)
@@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
  */
 u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 {
-       struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
        struct rsnd_mod *target;
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        u32 val = 0x76543210;
@@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        if (rsnd_io_is_play(io)) {
                struct rsnd_mod *src = rsnd_io_to_mod_src(io);
 
-               target = src ? src : ssi;
+               target = src ? src : ssiu;
        } else {
                struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
 
-               target = cmd ? cmd : ssi;
+               target = cmd ? cmd : ssiu;
        }
 
        mask <<= runtime->channels * 4;
@@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 /*
  *     rsnd_dai functions
  */
-#define rsnd_mod_call(idx, io, func, param...)                 \
-({                                                             \
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
-       struct rsnd_mod *mod = (io)->mod[idx];                  \
-       struct device *dev = rsnd_priv_to_dev(priv);            \
-       u32 *status = mod->get_status(io, mod, idx);                    \
-       u32 mask = 0xF << __rsnd_mod_shift_##func;                      \
-       u8 val  = (*status >> __rsnd_mod_shift_##func) & 0xF;           \
-       u8 add  = ((val + __rsnd_mod_add_##func) & 0xF);                \
-       int ret = 0;                                                    \
-       int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
-       if (add == 0xF)                                                 \
-               call = 0;                                               \
-       else                                                            \
-               *status = (*status & ~mask) +                           \
-                       (add << __rsnd_mod_shift_##func);               \
-       dev_dbg(dev, "%s[%d]\t0x%08x %s\n",                             \
-               rsnd_mod_name(mod), rsnd_mod_id(mod),                   \
-               *status, call ? #func : "");                            \
-       if (call)                                                       \
-               ret = (mod)->ops->func(mod, io, param);                 \
-       if (ret)                                                        \
-               dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n",       \
-                       rsnd_mod_name(mod), rsnd_mod_id(mod), ret);     \
-       ret;                                                            \
-})
+struct rsnd_mod *rsnd_mod_next(int *iterator,
+                              struct rsnd_dai_stream *io,
+                              enum rsnd_mod_type *array,
+                              int array_size)
+{
+       struct rsnd_mod *mod;
+       enum rsnd_mod_type type;
+       int max = array ? array_size : RSND_MOD_MAX;
+
+       for (; *iterator < max; (*iterator)++) {
+               type = (array) ? array[*iterator] : *iterator;
+               mod = io->mod[type];
+               if (!mod)
+                       continue;
+
+               (*iterator)++;
+
+               return mod;
+       }
+
+       return NULL;
+}
 
 static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
        {
@@ -409,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
        },
 };
 
-#define rsnd_dai_call(fn, io, param...)                                \
-({                                                             \
-       struct rsnd_mod *mod;                                   \
-       int type, is_play = rsnd_io_is_play(io);                \
-       int ret = 0, i;                                         \
-       for (i = 0; i < RSND_MOD_MAX; i++) {                    \
-               type = rsnd_mod_sequence[is_play][i];           \
-               mod = (io)->mod[type];                          \
-               if (!mod)                                       \
-                       continue;                               \
-               ret |= rsnd_mod_call(type, io, fn, param);      \
-       }                                                       \
-       ret;                                                    \
+static int rsnd_status_update(u32 *status,
+                             int shift, int add, int timing)
+{
+       u32 mask        = 0xF << shift;
+       u8 val          = (*status >> shift) & 0xF;
+       u8 next_val     = (val + add) & 0xF;
+       int func_call   = (val == timing);
+
+       if (next_val == 0xF) /* underflow case */
+               func_call = 0;
+       else
+               *status = (*status & ~mask) + (next_val << shift);
+
+       return func_call;
+}
+
+#define rsnd_dai_call(fn, io, param...)                                        \
+({                                                                     \
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);                   \
+       struct device *dev = rsnd_priv_to_dev(priv);                    \
+       struct rsnd_mod *mod;                                           \
+       int is_play = rsnd_io_is_play(io);                              \
+       int ret = 0, i;                                                 \
+       enum rsnd_mod_type *types = rsnd_mod_sequence[is_play];         \
+       for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) {     \
+               int tmp = 0;                                            \
+               u32 *status = mod->get_status(io, mod, types[i]);       \
+               int func_call = rsnd_status_update(status,              \
+                                               __rsnd_mod_shift_##fn,  \
+                                               __rsnd_mod_add_##fn,    \
+                                               __rsnd_mod_call_##fn);  \
+               dev_dbg(dev, "%s[%d]\t0x%08x %s\n",                     \
+                       rsnd_mod_name(mod), rsnd_mod_id(mod), *status,  \
+                       (func_call && (mod)->ops->fn) ? #fn : "");      \
+               if (func_call && (mod)->ops->fn)                        \
+                       tmp = (mod)->ops->fn(mod, io, param);           \
+               if (tmp)                                                \
+                       dev_err(dev, "%s[%d] : %s error %d\n",          \
+                               rsnd_mod_name(mod), rsnd_mod_id(mod),   \
+                                                    #fn, tmp);         \
+               ret |= tmp;                                             \
+       }                                                               \
+       ret;                                                            \
 })
 
 int rsnd_dai_connect(struct rsnd_mod *mod,
@@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
        return 0;
 }
 
+static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+       /*
+        * call rsnd_dai_call without spinlock
+        */
+       return rsnd_dai_call(nolock_start, io, priv);
+}
+
+static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+       /*
+        * call rsnd_dai_call without spinlock
+        */
+       rsnd_dai_call(nolock_stop, io, priv);
+}
+
 static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+       .startup        = rsnd_soc_dai_startup,
+       .shutdown       = rsnd_soc_dai_shutdown,
        .trigger        = rsnd_soc_dai_trigger,
        .set_fmt        = rsnd_soc_dai_set_fmt,
        .set_tdm_slot   = rsnd_soc_set_dai_tdm_slot,
@@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
 
 void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg)
 {
-       snd_ctl_remove(cfg->card, cfg->kctrl);
+       if (cfg->card && cfg->kctrl)
+               snd_ctl_remove(cfg->card, cfg->kctrl);
+
+       cfg->card = NULL;
+       cfg->kctrl = NULL;
 }
 
 int rsnd_kctrl_new_m(struct rsnd_mod *mod,
@@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 
        return snd_pcm_lib_preallocate_pages_for_all(
                rtd->pcm,
-               SNDRV_DMA_TYPE_DEV,
-               rtd->card->snd_card->dev,
+               SNDRV_DMA_TYPE_CONTINUOUS,
+               snd_dma_continuous_data(GFP_KERNEL),
                PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 
@@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
        ret = rsnd_dai_call(probe, io, priv);
        if (ret == -EAGAIN) {
                struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+               struct rsnd_mod *mod;
                int i;
 
                /*
@@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
                 * remove all mod from io
                 * and, re connect ssi
                 */
-               for (i = 0; i < RSND_MOD_MAX; i++)
-                       rsnd_dai_disconnect((io)->mod[i], io, i);
+               for_each_rsnd_mod(i, mod, io)
+                       rsnd_dai_disconnect(mod, io, i);
                rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
 
                /*
@@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev)
        return ret;
 }
 
+static int rsnd_suspend(struct device *dev)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(dev);
+
+       rsnd_adg_clk_disable(priv);
+
+       return 0;
+}
+
+static int rsnd_resume(struct device *dev)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(dev);
+
+       rsnd_adg_clk_enable(priv);
+
+       return 0;
+}
+
+static struct dev_pm_ops rsnd_pm_ops = {
+       .suspend                = rsnd_suspend,
+       .resume                 = rsnd_resume,
+};
+
 static struct platform_driver rsnd_driver = {
        .driver = {
                .name   = "rcar_sound",
+               .pm     = &rsnd_pm_ops,
                .of_match_table = rsnd_of_match,
        },
        .probe          = rsnd_probe,
index 6bc93cbb3049a823f8b33b559478f2d1175a9052..1f405c83386759a1bfc7dbfd3ff51dba2ee33614 100644 (file)
 
 struct rsnd_dmaen {
        struct dma_chan         *chan;
+       dma_addr_t              dma_buf;
+       unsigned int            dma_len;
+       unsigned int            dma_period;
+       unsigned int            dma_cnt;
 };
 
 struct rsnd_dmapp {
@@ -34,6 +38,8 @@ struct rsnd_dmapp {
 
 struct rsnd_dma {
        struct rsnd_mod         mod;
+       struct rsnd_mod         *mod_from;
+       struct rsnd_mod         *mod_to;
        dma_addr_t              src_addr;
        dma_addr_t              dst_addr;
        union {
@@ -56,10 +62,38 @@ struct rsnd_dma_ctrl {
 /*
  *             Audio DMAC
  */
+#define rsnd_dmaen_sync(dmaen, io, i)  __rsnd_dmaen_sync(dmaen, io, i, 1)
+#define rsnd_dmaen_unsync(dmaen, io, i)        __rsnd_dmaen_sync(dmaen, io, i, 0)
+static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io,
+                             int i, int sync)
+{
+       struct device *dev = dmaen->chan->device->dev;
+       enum dma_data_direction dir;
+       int is_play = rsnd_io_is_play(io);
+       dma_addr_t buf;
+       int len, max;
+       size_t period;
+
+       len     = dmaen->dma_len;
+       period  = dmaen->dma_period;
+       max     = len / period;
+       i       = i % max;
+       buf     = dmaen->dma_buf + (period * i);
+
+       dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+       if (sync)
+               dma_sync_single_for_device(dev, buf, period, dir);
+       else
+               dma_sync_single_for_cpu(dev, buf, period, dir);
+}
+
 static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
                                  struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
        bool elapsed = false;
        unsigned long flags;
 
@@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
         */
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (rsnd_io_is_working(io))
+       if (rsnd_io_is_working(io)) {
+               rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt);
+
+               /*
+                * Next period is already started.
+                * Let's sync Next Next period
+                * see
+                *      rsnd_dmaen_start()
+                */
+               rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2);
+
                elapsed = rsnd_dai_pointer_update(io, io->byte_per_period);
 
+               dmaen->dma_cnt++;
+       }
+
        spin_unlock_irqrestore(&priv->lock, flags);
 
        if (elapsed)
@@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data)
        rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
 }
 
+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) ||
+           (mod_from && mod_to))
+               return NULL;
+
+       if (mod_from)
+               return rsnd_mod_dma_req(io, mod_from);
+       else
+               return rsnd_mod_dma_req(io, mod_to);
+}
+
 static int rsnd_dmaen_stop(struct rsnd_mod *mod,
                           struct rsnd_dai_stream *io,
                           struct rsnd_priv *priv)
@@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
        struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
 
-       dmaengine_terminate_all(dmaen->chan);
+       if (dmaen->chan) {
+               int is_play = rsnd_io_is_play(io);
+
+               dmaengine_terminate_all(dmaen->chan);
+               dma_unmap_single(dmaen->chan->device->dev,
+                                dmaen->dma_buf, dmaen->dma_len,
+                                is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       }
+
+       return 0;
+}
+
+static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod,
+                                  struct rsnd_dai_stream *io,
+                                  struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+       /*
+        * DMAEngine release uses mutex lock.
+        * Thus, it shouldn't be called under spinlock.
+        * Let's call it under nolock_start
+        */
+       if (dmaen->chan)
+               dma_release_channel(dmaen->chan);
+
+       dmaen->chan = NULL;
+
+       return 0;
+}
+
+static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       if (dmaen->chan) {
+               dev_err(dev, "it already has dma channel\n");
+               return -EIO;
+       }
+
+       /*
+        * DMAEngine request uses mutex lock.
+        * Thus, it shouldn't be called under spinlock.
+        * Let's call it under nolock_start
+        */
+       dmaen->chan = rsnd_dmaen_request_channel(io,
+                                                dma->mod_from,
+                                                dma->mod_to);
+       if (IS_ERR_OR_NULL(dmaen->chan)) {
+               int ret = PTR_ERR(dmaen->chan);
+
+               dmaen->chan = NULL;
+               dev_err(dev, "can't get dma channel\n");
+               return ret;
+       }
 
        return 0;
 }
@@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
        struct snd_pcm_substream *substream = io->substream;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct dma_async_tx_descriptor *desc;
+       struct dma_slave_config cfg = {};
+       dma_addr_t buf;
+       size_t len;
+       size_t period;
        int is_play = rsnd_io_is_play(io);
+       int i;
+       int ret;
+
+       cfg.direction   = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+       cfg.src_addr    = dma->src_addr;
+       cfg.dst_addr    = dma->dst_addr;
+       cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+       dev_dbg(dev, "%s[%d] %pad -> %pad\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               &cfg.src_addr, &cfg.dst_addr);
+
+       ret = dmaengine_slave_config(dmaen->chan, &cfg);
+       if (ret < 0)
+               return ret;
+
+       len     = snd_pcm_lib_buffer_bytes(substream);
+       period  = snd_pcm_lib_period_bytes(substream);
+       buf     = dma_map_single(dmaen->chan->device->dev,
+                                substream->runtime->dma_area,
+                                len,
+                                is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       if (dma_mapping_error(dmaen->chan->device->dev, buf)) {
+               dev_err(dev, "dma map failed\n");
+               return -EIO;
+       }
 
        desc = dmaengine_prep_dma_cyclic(dmaen->chan,
-                                        substream->runtime->dma_addr,
-                                        snd_pcm_lib_buffer_bytes(substream),
-                                        snd_pcm_lib_period_bytes(substream),
+                                        buf, len, period,
                                         is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
                                         DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 
@@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
        desc->callback          = rsnd_dmaen_complete;
        desc->callback_param    = rsnd_mod_get(dma);
 
+       dmaen->dma_buf          = buf;
+       dmaen->dma_len          = len;
+       dmaen->dma_period       = period;
+       dmaen->dma_cnt          = 0;
+
+       /*
+        * synchronize this and next period
+        * see
+        *      __rsnd_dmaen_complete()
+        */
+       for (i = 0; i < 2; i++)
+               rsnd_dmaen_sync(dmaen, io, i);
+
        if (dmaengine_submit(desc) < 0) {
                dev_err(dev, "dmaengine_submit() fail\n");
                return -EIO;
@@ -143,124 +305,55 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
                                          struct rsnd_mod *mod, char *name)
 {
-       struct dma_chan *chan;
+       struct dma_chan *chan = NULL;
        struct device_node *np;
        int i = 0;
 
        for_each_child_of_node(of_node, np) {
-               if (i == rsnd_mod_id(mod))
-                       break;
+               if (i == rsnd_mod_id(mod) && (!chan))
+                       chan = of_dma_request_slave_channel(np, name);
                i++;
        }
 
-       chan = of_dma_request_slave_channel(np, name);
-
-       of_node_put(np);
+       /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */
        of_node_put(of_node);
 
        return chan;
 }
 
-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) ||
-           (mod_from && mod_to))
-               return NULL;
-
-       if (mod_from)
-               return rsnd_mod_dma_req(io, mod_from);
-       else
-               return rsnd_mod_dma_req(io, mod_to);
-}
-
-static int rsnd_dmaen_remove(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-
-       if (dmaen->chan)
-               dma_release_channel(dmaen->chan);
-
-       dmaen->chan = NULL;
-
-       return 0;
-}
-
 static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
-                          struct rsnd_dma *dma, int id,
+                          struct rsnd_dma *dma,
                           struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
-       struct rsnd_mod *mod = rsnd_mod_get(dma);
-       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct dma_slave_config cfg = {};
-       int is_play = rsnd_io_is_play(io);
-       int ret;
-
-       if (dmaen->chan) {
-               dev_err(dev, "it already has dma channel\n");
-               return -EIO;
-       }
-
-       if (dev->of_node) {
-               dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
-       } else {
-               dma_cap_mask_t mask;
-
-               dma_cap_zero(mask);
-               dma_cap_set(DMA_SLAVE, mask);
+       struct dma_chan *chan;
 
-               dmaen->chan = dma_request_channel(mask, shdma_chan_filter,
-                                                 (void *)(uintptr_t)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;
+       /* try to get DMAEngine channel */
+       chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
+       if (IS_ERR_OR_NULL(chan)) {
+               /*
+                * DMA failed. try to PIO mode
+                * see
+                *      rsnd_ssi_fallback()
+                *      rsnd_rdai_continuance_probe()
+                */
+               return -EAGAIN;
        }
 
-       cfg.direction   = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-       cfg.src_addr    = dma->src_addr;
-       cfg.dst_addr    = dma->dst_addr;
-       cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-
-       dev_dbg(dev, "%s[%d] %pad -> %pad\n",
-               rsnd_mod_name(mod), rsnd_mod_id(mod),
-               &cfg.src_addr, &cfg.dst_addr);
-
-       ret = dmaengine_slave_config(dmaen->chan, &cfg);
-       if (ret < 0)
-               goto rsnd_dma_attach_err;
+       dma_release_channel(chan);
 
        dmac->dmaen_num++;
 
        return 0;
-
-rsnd_dma_attach_err:
-       rsnd_dmaen_remove(mod, io, priv);
-rsnd_dma_channel_err:
-
-       /*
-        * DMA failed. try to PIO mode
-        * see
-        *      rsnd_ssi_fallback()
-        *      rsnd_rdai_continuance_probe()
-        */
-       return -EAGAIN;
 }
 
 static struct rsnd_mod_ops rsnd_dmaen_ops = {
        .name   = "audmac",
+       .nolock_start = rsnd_dmaen_nolock_start,
+       .nolock_stop  = rsnd_dmaen_nolock_stop,
        .start  = rsnd_dmaen_start,
        .stop   = rsnd_dmaen_stop,
-       .remove = rsnd_dmaen_remove,
 };
 
 /*
@@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod,
 }
 
 static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
-                            struct rsnd_dma *dma, int id,
+                            struct rsnd_dma *dma,
                             struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
 {
        struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
@@ -627,7 +720,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this,
 }
 
 int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
-                   struct rsnd_mod **dma_mod, int id)
+                   struct rsnd_mod **dma_mod)
 {
        struct rsnd_mod *mod_from = NULL;
        struct rsnd_mod *mod_to = NULL;
@@ -636,7 +729,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_mod_ops *ops;
        enum rsnd_mod_type type;
-       int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
+       int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,
                      struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
        int is_play = rsnd_io_is_play(io);
        int ret, dma_id;
@@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
 
                *dma_mod = rsnd_mod_get(dma);
 
-               dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
-               dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
-
                ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
                                    rsnd_mod_get_status, type, dma_id);
                if (ret < 0)
@@ -695,9 +785,14 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
                        rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
                        rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to));
 
-               ret = attach(io, dma, id, mod_from, mod_to);
+               ret = attach(io, dma, mod_from, mod_to);
                if (ret < 0)
                        return ret;
+
+               dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
+               dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
+               dma->mod_from = mod_from;
+               dma->mod_to   = mod_to;
        }
 
        ret = rsnd_dai_connect(*dma_mod, io, type);
index 02d971f69eff78731df462937bcc69a50149dff3..cf8f59cdd8d7fc47ec1ad5d40519cd26bbc1e9bc 100644 (file)
@@ -48,8 +48,6 @@ struct rsnd_dvc {
 
 #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
 #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
-#define rsnd_dvc_of_node(priv) \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
 
 #define rsnd_mod_to_dvc(_mod)  \
        container_of((_mod), struct rsnd_dvc, mod)
index 7d2fdf8dd1882f7188b4e2a33e7e771dfbe064dc..63b6d3c28021024b1f06278c5c4f217a394faf8c 100644 (file)
@@ -211,6 +211,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
                RSND_GEN_S_REG(SSI_MODE1,       0x804),
                RSND_GEN_S_REG(SSI_MODE2,       0x808),
                RSND_GEN_S_REG(SSI_CONTROL,     0x810),
+               RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
+               RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
+               RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
+               RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
+               RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
+               RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
+               RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
+               RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
 
                /* FIXME: it needs SSI_MODE2/3 in the future */
                RSND_GEN_M_REG(SSI_BUSIF_MODE,  0x0,    0x80),
@@ -311,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
        static const struct rsnd_regmap_field_conf conf_adg[] = {
                RSND_GEN_S_REG(BRRA,            0x00),
                RSND_GEN_S_REG(BRRB,            0x04),
-               RSND_GEN_S_REG(SSICKR,          0x08),
+               RSND_GEN_S_REG(BRGCKR,          0x08),
                RSND_GEN_S_REG(AUDIO_CLK_SEL0,  0x0c),
                RSND_GEN_S_REG(AUDIO_CLK_SEL1,  0x10),
                RSND_GEN_S_REG(AUDIO_CLK_SEL2,  0x14),
@@ -362,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv)
        static const struct rsnd_regmap_field_conf conf_adg[] = {
                RSND_GEN_S_REG(BRRA,            0x00),
                RSND_GEN_S_REG(BRRB,            0x04),
-               RSND_GEN_S_REG(SSICKR,          0x08),
+               RSND_GEN_S_REG(BRGCKR,          0x08),
                RSND_GEN_S_REG(AUDIO_CLK_SEL0,  0x0c),
                RSND_GEN_S_REG(AUDIO_CLK_SEL1,  0x10),
        };
index a8f61d79333b5071c8fb6785458c4e87aca3158b..b90df77662dfa337e5ff50bb44ef59efa1eef6e6 100644 (file)
  * see gen1/gen2 for detail
  */
 enum rsnd_reg {
-       /* SCU (SRC/SSIU/MIX/CTU/DVC) */
-       RSND_REG_SSI_MODE,              /* Gen2 only */
-       RSND_REG_SSI_MODE0,
-       RSND_REG_SSI_MODE1,
-       RSND_REG_SSI_MODE2,
-       RSND_REG_SSI_CONTROL,
-       RSND_REG_SSI_CTRL,              /* Gen2 only */
-       RSND_REG_SSI_BUSIF_MODE,        /* Gen2 only */
-       RSND_REG_SSI_BUSIF_ADINR,       /* Gen2 only */
-       RSND_REG_SSI_BUSIF_DALIGN,      /* Gen2 only */
-       RSND_REG_SSI_INT_ENABLE,        /* Gen2 only */
+       /* SCU (MIX/CTU/DVC) */
        RSND_REG_SRC_I_BUSIF_MODE,
        RSND_REG_SRC_O_BUSIF_MODE,
        RSND_REG_SRC_ROUTE_MODE0,
@@ -63,29 +53,29 @@ enum rsnd_reg {
        RSND_REG_SRC_IFSCR,
        RSND_REG_SRC_IFSVR,
        RSND_REG_SRC_SRCCR,
-       RSND_REG_SRC_CTRL,              /* Gen2 only */
-       RSND_REG_SRC_BSDSR,             /* Gen2 only */
-       RSND_REG_SRC_BSISR,             /* Gen2 only */
-       RSND_REG_SRC_INT_ENABLE0,       /* Gen2 only */
-       RSND_REG_SRC_BUSIF_DALIGN,      /* Gen2 only */
-       RSND_REG_SRCIN_TIMSEL0,         /* Gen2 only */
-       RSND_REG_SRCIN_TIMSEL1,         /* Gen2 only */
-       RSND_REG_SRCIN_TIMSEL2,         /* Gen2 only */
-       RSND_REG_SRCIN_TIMSEL3,         /* Gen2 only */
-       RSND_REG_SRCIN_TIMSEL4,         /* Gen2 only */
-       RSND_REG_SRCOUT_TIMSEL0,        /* Gen2 only */
-       RSND_REG_SRCOUT_TIMSEL1,        /* Gen2 only */
-       RSND_REG_SRCOUT_TIMSEL2,        /* Gen2 only */
-       RSND_REG_SRCOUT_TIMSEL3,        /* Gen2 only */
-       RSND_REG_SRCOUT_TIMSEL4,        /* Gen2 only */
+       RSND_REG_SRC_CTRL,
+       RSND_REG_SRC_BSDSR,
+       RSND_REG_SRC_BSISR,
+       RSND_REG_SRC_INT_ENABLE0,
+       RSND_REG_SRC_BUSIF_DALIGN,
+       RSND_REG_SRCIN_TIMSEL0,
+       RSND_REG_SRCIN_TIMSEL1,
+       RSND_REG_SRCIN_TIMSEL2,
+       RSND_REG_SRCIN_TIMSEL3,
+       RSND_REG_SRCIN_TIMSEL4,
+       RSND_REG_SRCOUT_TIMSEL0,
+       RSND_REG_SRCOUT_TIMSEL1,
+       RSND_REG_SRCOUT_TIMSEL2,
+       RSND_REG_SRCOUT_TIMSEL3,
+       RSND_REG_SRCOUT_TIMSEL4,
        RSND_REG_SCU_SYS_STATUS0,
-       RSND_REG_SCU_SYS_STATUS1,       /* Gen2 only */
+       RSND_REG_SCU_SYS_STATUS1,
        RSND_REG_SCU_SYS_INT_EN0,
-       RSND_REG_SCU_SYS_INT_EN1,       /* Gen2 only */
-       RSND_REG_CMD_CTRL,              /* Gen2 only */
-       RSND_REG_CMD_BUSIF_DALIGN,      /* Gen2 only */
+       RSND_REG_SCU_SYS_INT_EN1,
+       RSND_REG_CMD_CTRL,
+       RSND_REG_CMD_BUSIF_DALIGN,
        RSND_REG_CMD_ROUTE_SLCT,
-       RSND_REG_CMDOUT_TIMSEL,         /* Gen2 only */
+       RSND_REG_CMDOUT_TIMSEL,
        RSND_REG_CTU_SWRSR,
        RSND_REG_CTU_CTUIR,
        RSND_REG_CTU_ADINR,
@@ -147,18 +137,38 @@ enum rsnd_reg {
        RSND_REG_DVC_VOL6R,
        RSND_REG_DVC_VOL7R,
        RSND_REG_DVC_DVUER,
-       RSND_REG_DVC_VRCTR,             /* Gen2 only */
-       RSND_REG_DVC_VRPDR,             /* Gen2 only */
-       RSND_REG_DVC_VRDBR,             /* Gen2 only */
+       RSND_REG_DVC_VRCTR,
+       RSND_REG_DVC_VRPDR,
+       RSND_REG_DVC_VRDBR,
 
        /* ADG */
        RSND_REG_BRRA,
        RSND_REG_BRRB,
-       RSND_REG_SSICKR,
-       RSND_REG_DIV_EN,                /* Gen2 only */
+       RSND_REG_BRGCKR,
+       RSND_REG_DIV_EN,
        RSND_REG_AUDIO_CLK_SEL0,
        RSND_REG_AUDIO_CLK_SEL1,
-       RSND_REG_AUDIO_CLK_SEL2,        /* Gen2 only */
+       RSND_REG_AUDIO_CLK_SEL2,
+
+       /* SSIU */
+       RSND_REG_SSI_MODE,
+       RSND_REG_SSI_MODE0,
+       RSND_REG_SSI_MODE1,
+       RSND_REG_SSI_MODE2,
+       RSND_REG_SSI_CONTROL,
+       RSND_REG_SSI_CTRL,
+       RSND_REG_SSI_BUSIF_MODE,
+       RSND_REG_SSI_BUSIF_ADINR,
+       RSND_REG_SSI_BUSIF_DALIGN,
+       RSND_REG_SSI_INT_ENABLE,
+       RSND_REG_SSI_SYS_STATUS0,
+       RSND_REG_SSI_SYS_STATUS1,
+       RSND_REG_SSI_SYS_STATUS2,
+       RSND_REG_SSI_SYS_STATUS3,
+       RSND_REG_SSI_SYS_STATUS4,
+       RSND_REG_SSI_SYS_STATUS5,
+       RSND_REG_SSI_SYS_STATUS6,
+       RSND_REG_SSI_SYS_STATUS7,
 
        /* SSI */
        RSND_REG_SSICR,
@@ -199,7 +209,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
  *     R-Car DMA
  */
 int rsnd_dma_attach(struct rsnd_dai_stream *io,
-                   struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id);
+                   struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
 int rsnd_dma_probe(struct rsnd_priv *priv);
 struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
                                          struct rsnd_mod *mod, char *name);
@@ -259,6 +269,12 @@ struct rsnd_mod_ops {
        int (*fallback)(struct rsnd_mod *mod,
                        struct rsnd_dai_stream *io,
                        struct rsnd_priv *priv);
+       int (*nolock_start)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
+                   struct rsnd_priv *priv);
+       int (*nolock_stop)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
+                   struct rsnd_priv *priv);
 };
 
 struct rsnd_dai_stream;
@@ -278,7 +294,7 @@ struct rsnd_mod {
  *
  * 0xH0000CBA
  *
- * A   0: probe        1: remove
+ * A   0: nolock_start 1: nolock_stop
  * B   0: init         1: quit
  * C   0: start        1: stop
  *
@@ -288,19 +304,23 @@ struct rsnd_mod {
  * H   0: fallback
  * H   0: hw_params
  */
-#define __rsnd_mod_shift_probe         0
-#define __rsnd_mod_shift_remove                0
+#define __rsnd_mod_shift_nolock_start  0
+#define __rsnd_mod_shift_nolock_stop   0
 #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_probe         28 /* always called */
+#define __rsnd_mod_shift_remove                28 /* always called */
 #define __rsnd_mod_shift_irq           28 /* always called */
 #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_probe           0
+#define __rsnd_mod_add_remove          0
+#define __rsnd_mod_add_nolock_start     1
+#define __rsnd_mod_add_nolock_stop     -1
 #define __rsnd_mod_add_init             1
 #define __rsnd_mod_add_quit            -1
 #define __rsnd_mod_add_start            1
@@ -311,7 +331,7 @@ struct rsnd_mod {
 #define __rsnd_mod_add_hw_params       0
 
 #define __rsnd_mod_call_probe          0
-#define __rsnd_mod_call_remove         1
+#define __rsnd_mod_call_remove         0
 #define __rsnd_mod_call_init           0
 #define __rsnd_mod_call_quit           1
 #define __rsnd_mod_call_start          0
@@ -320,6 +340,8 @@ struct rsnd_mod {
 #define __rsnd_mod_call_pcm_new                0
 #define __rsnd_mod_call_fallback       0
 #define __rsnd_mod_call_hw_params      0
+#define __rsnd_mod_call_nolock_start   0
+#define __rsnd_mod_call_nolock_stop    1
 
 #define rsnd_mod_to_priv(mod) ((mod)->priv)
 #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
@@ -346,6 +368,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
 u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
                         struct rsnd_mod *mod,
                         enum rsnd_mod_type type);
+struct rsnd_mod *rsnd_mod_next(int *iterator,
+                              struct rsnd_dai_stream *io,
+                              enum rsnd_mod_type *array,
+                              int array_size);
+#define for_each_rsnd_mod(iterator, pos, io)                           \
+       for (iterator = 0;                                              \
+            (pos = rsnd_mod_next(&iterator, io, NULL, 0));)
+#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size)       \
+       for (iterator = 0;                                              \
+            (pos = rsnd_mod_next(&iterator, io, array, size));)
+#define for_each_rsnd_mod_array(iterator, pos, io, array)              \
+       for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))
 
 void rsnd_parse_connect_common(struct rsnd_dai *rdai,
                struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
@@ -364,6 +398,18 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io);
 int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
 int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
 
+/*
+ * DT
+ */
+#define rsnd_parse_of_node(priv, node)                                 \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
+#define RSND_NODE_DAI  "rcar_sound,dai"
+#define RSND_NODE_SSI  "rcar_sound,ssi"
+#define RSND_NODE_SRC  "rcar_sound,src"
+#define RSND_NODE_CTU  "rcar_sound,ctu"
+#define RSND_NODE_MIX  "rcar_sound,mix"
+#define RSND_NODE_DVC  "rcar_sound,dvc"
+
 /*
  *     R-Car sound DAI
  */
@@ -382,6 +428,7 @@ struct rsnd_dai_stream {
 };
 #define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
 #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
+#define rsnd_io_to_mod_ssiu(io)        rsnd_io_to_mod((io), RSND_MOD_SSIU)
 #define rsnd_io_to_mod_ssip(io)        rsnd_io_to_mod((io), RSND_MOD_SSIP)
 #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
 #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
@@ -428,8 +475,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
 int rsnd_dai_connect(struct rsnd_mod *mod,
                     struct rsnd_dai_stream *io,
                     enum rsnd_mod_type type);
-#define rsnd_dai_of_node(priv)                                         \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
+#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
 
 /*
  *     R-Car Gen1/Gen2
@@ -453,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
                                  unsigned int out_rate);
 int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
                                 struct rsnd_dai_stream *io);
+#define rsnd_adg_clk_enable(priv)      rsnd_adg_clk_control(priv, 1)
+#define rsnd_adg_clk_disable(priv)     rsnd_adg_clk_control(priv, 0)
+void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
 
 /*
  *     R-Car sound priv
@@ -606,8 +655,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
        __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
 int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 
-#define rsnd_ssi_of_node(priv)                                         \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
+#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI)
 void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
                            struct device_node *playback,
                            struct device_node *capture);
@@ -633,8 +681,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
                               struct rsnd_dai_stream *io,
                               int is_in);
 
-#define rsnd_src_of_node(priv)                                         \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
+#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)
 #define rsnd_parse_connect_src(rdai, playback, capture)                        \
        rsnd_parse_connect_common(rdai, rsnd_src_mod_get,               \
                                  rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
@@ -647,8 +694,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv);
 void rsnd_ctu_remove(struct rsnd_priv *priv);
 int rsnd_ctu_converted_channel(struct rsnd_mod *mod);
 struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
-#define rsnd_ctu_of_node(priv)                                         \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
+#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
 #define rsnd_parse_connect_ctu(rdai, playback, capture)                        \
        rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get,               \
                                  rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
@@ -660,8 +706,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_mix_probe(struct rsnd_priv *priv);
 void rsnd_mix_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
-#define rsnd_mix_of_node(priv)                                         \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
+#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
 #define rsnd_parse_connect_mix(rdai, playback, capture)                        \
        rsnd_parse_connect_common(rdai, rsnd_mix_mod_get,               \
                                  rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
@@ -673,8 +718,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_dvc_probe(struct rsnd_priv *priv);
 void rsnd_dvc_remove(struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
-#define rsnd_dvc_of_node(priv)                                         \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
+#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
 #define rsnd_parse_connect_dvc(rdai, playback, capture)                        \
        rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get,               \
                                  rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
index 969a5169de255a2fe66202ffc89808c89bfe98ec..3a8f65bd1bf95c17afbe3a0f43b7ad1b94409792 100644 (file)
@@ -189,6 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       int use_src = 0;
        u32 fin, fout;
        u32 ifscr, fsrate, adinr;
        u32 cr, route;
@@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
                return;
        }
 
+       use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
+
        /*
         *      SRC_ADINR
         */
@@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
         */
        ifscr = 0;
        fsrate = 0;
-       if (fin != fout) {
+       if (use_src) {
                u64 n;
 
                ifscr = 1;
@@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
         */
        cr      = 0x00011110;
        route   = 0x0;
-       if (fin != fout) {
+       if (use_src) {
                route   = 0x1;
 
                if (rsnd_src_sync_is_enabled(mod)) {
@@ -327,8 +330,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod)
 {
        u32 val = OUF_SRC(rsnd_mod_id(mod));
 
-       rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val);
-       rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
+       rsnd_mod_write(mod, SCU_SYS_STATUS0, val);
+       rsnd_mod_write(mod, SCU_SYS_STATUS1, val);
 }
 
 static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
@@ -475,7 +478,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod,
                        return ret;
        }
 
-       ret = rsnd_dma_attach(io, mod, &src->dma, 0);
+       ret = rsnd_dma_attach(io, mod, &src->dma);
 
        return ret;
 }
index 6cb6db005fc45dd3e562fe480c0e353db7a6116a..411bda2387adbcdab2dc510706986f5ac92b3cc1 100644 (file)
@@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
        int chan = params_channels(params);
 
        /*
-        * Already working.
-        * It will happen if SSI has parent/child connection.
+        * snd_pcm_ops::hw_params will be called *before*
+        * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0
+        * in 1st call.
         */
-       if (ssi->usrcnt > 1) {
+       if (ssi->usrcnt) {
                /*
+                * Already working.
+                * It will happen if SSI has parent/child connection.
                 * it is error if child <-> parent SSI uses
                 * different channels.
                 */
@@ -644,10 +647,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = devm_request_irq(dev, ssi->irq,
-                              rsnd_ssi_interrupt,
-                              IRQF_SHARED,
-                              dev_name(dev), mod);
+       /*
+        * SSI might be called again as PIO fallback
+        * It is easy to manual handling for IRQ request/free
+        */
+       ret = request_irq(ssi->irq,
+                         rsnd_ssi_interrupt,
+                         IRQF_SHARED,
+                         dev_name(dev), mod);
 
        return ret;
 }
@@ -669,7 +676,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
                              struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       int dma_id = 0; /* not needed */
        int ret;
 
        /*
@@ -684,7 +690,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
                return ret;
 
        /* SSI probe might be called many times in MUX multi path */
-       ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id);
+       ret = rsnd_dma_attach(io, mod, &ssi->dma);
 
        return ret;
 }
@@ -694,11 +700,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
                               struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int irq = ssi->irq;
 
        /* PIO will request IRQ again */
-       devm_free_irq(dev, irq, mod);
+       free_irq(ssi->irq, mod);
 
        return 0;
 }
index 6f9b388ec5a8f0c2095a2a88e33d725244706b2e..4e817c8a18c0bbe899374028ae56ef0754042d59 100644 (file)
@@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
        u32 mask1, val1;
        u32 mask2, val2;
 
+       /* clear status */
+       switch (id) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+               rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4));
+               rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4));
+               rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4));
+               rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4));
+               break;
+       case 9:
+               rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4);
+               rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4);
+               rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4);
+               rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4);
+               break;
+       }
+
        /*
         * SSI_MODE0
         */
index bf7b52fce597422cc2a2c171b9d6ac97c4e0c1e2..bfd71b873ca27ea981720cb5f747ddc34ef51438 100644 (file)
@@ -30,16 +30,26 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
+               ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
+               if (ret < 0) {
+                       dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n",
+                               cpu_dai->name, ret);
+                       goto out;
+               }
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
                ret = platform->driver->compr_ops->open(cstream);
                if (ret < 0) {
                        pr_err("compress asoc: can't open platform %s\n",
                                platform->component.name);
-                       goto out;
+                       goto plat_err;
                }
        }
 
@@ -60,6 +70,9 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
 machine_err:
        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
                platform->driver->compr_ops->free(cstream);
+plat_err:
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
+               cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
 out:
        mutex_unlock(&rtd->pcm_mutex);
        return ret;
@@ -70,6 +83,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
        struct snd_soc_platform *platform = fe->platform;
+       struct snd_soc_dai *cpu_dai = fe->cpu_dai;
        struct snd_soc_dpcm *dpcm;
        struct snd_soc_dapm_widget_list *list;
        int stream;
@@ -82,12 +96,22 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
+               ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
+               if (ret < 0) {
+                       dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n",
+                               cpu_dai->name, ret);
+                       goto out;
+               }
+       }
+
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
                ret = platform->driver->compr_ops->open(cstream);
                if (ret < 0) {
                        pr_err("compress asoc: can't open platform %s\n",
                                platform->component.name);
-                       goto out;
+                       goto plat_err;
                }
        }
 
@@ -144,6 +168,9 @@ fe_err:
 machine_err:
        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
                platform->driver->compr_ops->free(cstream);
+plat_err:
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
+               cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
 out:
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
        mutex_unlock(&fe->card->mutex);
@@ -210,6 +237,9 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
                platform->driver->compr_ops->free(cstream);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
+               cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
+
        if (cstream->direction == SND_COMPRESS_PLAYBACK) {
                if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
                        snd_soc_dapm_stream_event(rtd,
@@ -236,6 +266,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 {
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_soc_platform *platform = fe->platform;
+       struct snd_soc_dai *cpu_dai = fe->cpu_dai;
        struct snd_soc_dpcm *dpcm;
        int stream, ret;
 
@@ -275,6 +306,9 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
        if (platform->driver->compr_ops && platform->driver->compr_ops->free)
                platform->driver->compr_ops->free(cstream);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
+               cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
+
        mutex_unlock(&fe->card->mutex);
        return 0;
 }
@@ -285,6 +319,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -295,6 +330,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
                        goto out;
        }
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger)
+               cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
+
+
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
@@ -313,6 +352,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 {
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_soc_platform *platform = fe->platform;
+       struct snd_soc_dai *cpu_dai = fe->cpu_dai;
        int ret = 0, stream;
 
        if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
@@ -332,6 +372,12 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) {
+               ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai);
+               if (ret < 0)
+                       goto out;
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
                ret = platform->driver->compr_ops->trigger(cstream, cmd);
                if (ret < 0)
@@ -368,6 +414,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -378,6 +425,12 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
         * expectation is that platform and machine will configure everything
         * for this compress path, like configuring pcm port for codec
         */
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
+               ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
+               if (ret < 0)
+                       goto err;
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
                ret = platform->driver->compr_ops->set_params(cstream, params);
                if (ret < 0)
@@ -416,6 +469,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
        struct snd_soc_pcm_runtime *fe = cstream->private_data;
        struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
        struct snd_soc_platform *platform = fe->platform;
+       struct snd_soc_dai *cpu_dai = fe->cpu_dai;
        int ret = 0, stream;
 
        if (cstream->direction == SND_COMPRESS_PLAYBACK)
@@ -425,6 +479,12 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
+               ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
+               if (ret < 0)
+                       goto out;
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
                ret = platform->driver->compr_ops->set_params(cstream, params);
                if (ret < 0)
@@ -469,13 +529,21 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream,
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) {
+               ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai);
+               if (ret < 0)
+                       goto err;
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
                ret = platform->driver->compr_ops->get_params(cstream, params);
 
+err:
        mutex_unlock(&rtd->pcm_mutex);
        return ret;
 }
@@ -516,13 +584,21 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) {
+               ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai);
+               if (ret < 0)
+                       goto err;
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
                ret = platform->driver->compr_ops->ack(cstream, bytes);
 
+err:
        mutex_unlock(&rtd->pcm_mutex);
        return ret;
 }
@@ -533,9 +609,13 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream,
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
        int ret = 0;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer)
+               cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai);
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
                ret = platform->driver->compr_ops->pointer(cstream, tstamp);
 
@@ -564,8 +644,15 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) {
+               ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai);
+               if (ret < 0)
+                       return ret;
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
                ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
 
@@ -577,8 +664,15 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
+       if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) {
+               ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai);
+               if (ret < 0)
+                       return ret;
+       }
+
        if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
                ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
 
index c0bbcd9032613a78aef551ce697cabc792880bad..ce8e665a9c894f507882e008557543978316c39d 100644 (file)
@@ -626,7 +626,7 @@ static void codec2codec_close_delayed_work(struct work_struct *work)
 int snd_soc_suspend(struct device *dev)
 {
        struct snd_soc_card *card = dev_get_drvdata(dev);
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
        struct snd_soc_pcm_runtime *rtd;
        int i;
 
@@ -702,39 +702,39 @@ int snd_soc_suspend(struct device *dev)
        dapm_mark_endpoints_dirty(card);
        snd_soc_dapm_sync(&card->dapm);
 
-       /* suspend all CODECs */
-       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       /* suspend all COMPONENTs */
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
-               /* If there are paths active then the CODEC will be held with
+               /* If there are paths active then the COMPONENT will be held with
                 * bias _ON and should not be suspended. */
-               if (!codec->suspended) {
+               if (!component->suspended) {
                        switch (snd_soc_dapm_get_bias_level(dapm)) {
                        case SND_SOC_BIAS_STANDBY:
                                /*
-                                * If the CODEC is capable of idle
+                                * If the COMPONENT is capable of idle
                                 * bias off then being in STANDBY
                                 * means it's doing something,
                                 * otherwise fall through.
                                 */
                                if (dapm->idle_bias_off) {
-                                       dev_dbg(codec->dev,
+                                       dev_dbg(component->dev,
                                                "ASoC: idle_bias_off CODEC on over suspend\n");
                                        break;
                                }
 
                        case SND_SOC_BIAS_OFF:
-                               if (codec->driver->suspend)
-                                       codec->driver->suspend(codec);
-                               codec->suspended = 1;
-                               if (codec->component.regmap)
-                                       regcache_mark_dirty(codec->component.regmap);
+                               if (component->suspend)
+                                       component->suspend(component);
+                               component->suspended = 1;
+                               if (component->regmap)
+                                       regcache_mark_dirty(component->regmap);
                                /* deactivate pins to sleep state */
-                               pinctrl_pm_select_sleep_state(codec->dev);
+                               pinctrl_pm_select_sleep_state(component->dev);
                                break;
                        default:
-                               dev_dbg(codec->dev,
-                                       "ASoC: CODEC is on over suspend\n");
+                               dev_dbg(component->dev,
+                                       "ASoC: COMPONENT is on over suspend\n");
                                break;
                        }
                }
@@ -768,7 +768,7 @@ static void soc_resume_deferred(struct work_struct *work)
        struct snd_soc_card *card =
                        container_of(work, struct snd_soc_card, deferred_resume_work);
        struct snd_soc_pcm_runtime *rtd;
-       struct snd_soc_codec *codec;
+       struct snd_soc_component *component;
        int i;
 
        /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
@@ -794,11 +794,11 @@ static void soc_resume_deferred(struct work_struct *work)
                        cpu_dai->driver->resume(cpu_dai);
        }
 
-       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               if (codec->suspended) {
-                       if (codec->driver->resume)
-                               codec->driver->resume(codec);
-                       codec->suspended = 0;
+       list_for_each_entry(component, &card->component_dev_list, card_list) {
+               if (component->suspended) {
+                       if (component->resume)
+                               component->resume(component);
+                       component->suspended = 0;
                }
        }
 
@@ -993,6 +993,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
        struct snd_soc_dai_link_component cpu_dai_component;
        struct snd_soc_dai **codec_dais;
        struct snd_soc_platform *platform;
+       struct device_node *platform_of_node;
        const char *platform_name;
        int i;
 
@@ -1042,9 +1043,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
 
        /* find one from the set of registered platforms */
        list_for_each_entry(platform, &platform_list, list) {
+               platform_of_node = platform->dev->of_node;
+               if (!platform_of_node && platform->dev->parent->of_node)
+                       platform_of_node = platform->dev->parent->of_node;
+
                if (dai_link->platform_of_node) {
-                       if (platform->dev->of_node !=
-                           dai_link->platform_of_node)
+                       if (platform_of_node != dai_link->platform_of_node)
                                continue;
                } else {
                        if (strcmp(platform->component.name, platform_name))
@@ -1072,9 +1076,7 @@ static void soc_remove_component(struct snd_soc_component *component)
        if (!component->card)
                return;
 
-       /* This is a HACK and will be removed soon */
-       if (component->codec)
-               list_del(&component->codec->card_list);
+       list_del(&component->card_list);
 
        if (component->remove)
                component->remove(component);
@@ -1443,10 +1445,7 @@ static int soc_probe_component(struct snd_soc_card *card,
                                        component->num_dapm_routes);
 
        list_add(&dapm->list, &card->dapm_list);
-
-       /* This is a HACK and will be removed soon */
-       if (component->codec)
-               list_add(&component->codec->card_list, &card->codec_dev_list);
+       list_add(&component->card_list, &card->component_dev_list);
 
        return 0;
 
@@ -1706,7 +1705,8 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
        }
 
        component->init = aux_dev->init;
-       list_add(&component->list_aux, &card->aux_comp_list);
+       component->auxiliary = 1;
+
        return 0;
 
 err_defer:
@@ -1722,7 +1722,10 @@ static int soc_probe_aux_devices(struct snd_soc_card *card)
 
        for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
                order++) {
-               list_for_each_entry(comp, &card->aux_comp_list, list_aux) {
+               list_for_each_entry(comp, &card->component_dev_list, card_list) {
+                       if (!comp->auxiliary)
+                               continue;
+
                        if (comp->driver->probe_order == order) {
                                ret = soc_probe_component(card, comp);
                                if (ret < 0) {
@@ -1746,11 +1749,14 @@ static void soc_remove_aux_devices(struct snd_soc_card *card)
        for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
                order++) {
                list_for_each_entry_safe(comp, _comp,
-                       &card->aux_comp_list, list_aux) {
+                       &card->component_dev_list, card_list) {
+
+                       if (!comp->auxiliary)
+                               continue;
+
                        if (comp->driver->remove_order == order) {
                                soc_remove_component(comp);
-                               /* remove it from the card's aux_comp_list */
-                               list_del(&comp->list_aux);
+                               comp->auxiliary = 0;
                        }
                }
        }
@@ -2926,6 +2932,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
        component->driver = driver;
        component->probe = component->driver->probe;
        component->remove = component->driver->remove;
+       component->suspend = component->driver->suspend;
+       component->resume = component->driver->resume;
 
        dapm = &component->dapm;
        dapm->dev = dev;
@@ -3275,6 +3283,20 @@ static void snd_soc_codec_drv_remove(struct snd_soc_component *component)
        codec->driver->remove(codec);
 }
 
+static int snd_soc_codec_drv_suspend(struct snd_soc_component *component)
+{
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+       return codec->driver->suspend(codec);
+}
+
+static int snd_soc_codec_drv_resume(struct snd_soc_component *component)
+{
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+       return codec->driver->resume(codec);
+}
+
 static int snd_soc_codec_drv_write(struct snd_soc_component *component,
        unsigned int reg, unsigned int val)
 {
@@ -3336,6 +3358,10 @@ int snd_soc_register_codec(struct device *dev,
                codec->component.probe = snd_soc_codec_drv_probe;
        if (codec_drv->remove)
                codec->component.remove = snd_soc_codec_drv_remove;
+       if (codec_drv->suspend)
+               codec->component.suspend = snd_soc_codec_drv_suspend;
+       if (codec_drv->resume)
+               codec->component.resume = snd_soc_codec_drv_resume;
        if (codec_drv->write)
                codec->component.write = snd_soc_codec_drv_write;
        if (codec_drv->read)
@@ -3424,10 +3450,10 @@ found:
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
 /* Retrieve a card's name from device tree */
-int snd_soc_of_parse_card_name(struct snd_soc_card *card,
-                              const char *propname)
+int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card,
+                                        struct device_node *np,
+                                        const char *propname)
 {
-       struct device_node *np;
        int ret;
 
        if (!card->dev) {
@@ -3435,7 +3461,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
                return -EINVAL;
        }
 
-       np = card->dev->of_node;
+       if (!np)
+               np = card->dev->of_node;
 
        ret = of_property_read_string_index(np, propname, 0, &card->name);
        /*
@@ -3452,7 +3479,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name_from_node);
 
 static const struct snd_soc_dapm_widget simple_widgets[] = {
        SND_SOC_DAPM_MIC("Microphone", NULL),
@@ -3461,14 +3488,17 @@ static const struct snd_soc_dapm_widget simple_widgets[] = {
        SND_SOC_DAPM_SPK("Speaker", NULL),
 };
 
-int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
+int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card,
+                                         struct device_node *np,
                                          const char *propname)
 {
-       struct device_node *np = card->dev->of_node;
        struct snd_soc_dapm_widget *widgets;
        const char *template, *wname;
        int i, j, num_widgets, ret;
 
+       if (!np)
+               np = card->dev->of_node;
+
        num_widgets = of_property_count_strings(np, propname);
        if (num_widgets < 0) {
                dev_err(card->dev,
@@ -3539,7 +3569,7 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets_from_node);
 
 static int snd_soc_of_get_slot_mask(struct device_node *np,
                                    const char *prop_name,
@@ -3595,15 +3625,18 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
 
-void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card,
+                                  struct device_node *np,
                                   struct snd_soc_codec_conf *codec_conf,
                                   struct device_node *of_node,
                                   const char *propname)
 {
-       struct device_node *np = card->dev->of_node;
        const char *str;
        int ret;
 
+       if (!np)
+               np = card->dev->of_node;
+
        ret = of_property_read_string(np, propname, &str);
        if (ret < 0) {
                /* no prefix is not error */
@@ -3613,16 +3646,19 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
        codec_conf->of_node     = of_node;
        codec_conf->name_prefix = str;
 }
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix_from_node);
 
-int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
+int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card,
+                                  struct device_node *np,
                                   const char *propname)
 {
-       struct device_node *np = card->dev->of_node;
        int num_routes;
        struct snd_soc_dapm_route *routes;
        int i, ret;
 
+       if (!np)
+               np = card->dev->of_node;
+
        num_routes = of_property_count_strings(np, propname);
        if (num_routes < 0 || num_routes & 1) {
                dev_err(card->dev,
@@ -3669,7 +3705,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing_from_node);
 
 unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
                                     const char *prefix,
@@ -3784,7 +3820,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
 
-static int snd_soc_get_dai_name(struct of_phandle_args *args,
+int snd_soc_get_dai_name(struct of_phandle_args *args,
                                const char **dai_name)
 {
        struct snd_soc_component *pos;
@@ -3836,6 +3872,7 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args,
        mutex_unlock(&client_mutex);
        return ret;
 }
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_name);
 
 int snd_soc_of_get_dai_name(struct device_node *of_node,
                            const char **dai_name)
index 3bbe32ee4630479ae55ea22f28690eef538aa75b..27dd02e57b31b0083f00a7864005a8ca867c42fb 100644 (file)
@@ -330,6 +330,11 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
        case snd_soc_dapm_mixer_named_ctl:
                mc = (struct soc_mixer_control *)kcontrol->private_value;
 
+               if (mc->autodisable && snd_soc_volsw_is_stereo(mc))
+                       dev_warn(widget->dapm->dev,
+                                "ASoC: Unsupported stereo autodisable control '%s'\n",
+                                ctrl_name);
+
                if (mc->autodisable) {
                        struct snd_soc_dapm_widget template;
 
@@ -723,7 +728,8 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
 }
 
 /* set up initial codec paths */
-static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
+static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
+                                      int nth_path)
 {
        struct soc_mixer_control *mc = (struct soc_mixer_control *)
                p->sink->kcontrol_news[i].private_value;
@@ -736,7 +742,25 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
 
        if (reg != SND_SOC_NOPM) {
                soc_dapm_read(p->sink->dapm, reg, &val);
-               val = (val >> shift) & mask;
+               /*
+                * The nth_path argument allows this function to know
+                * which path of a kcontrol it is setting the initial
+                * status for. Ideally this would support any number
+                * of paths and channels. But since kcontrols only come
+                * in mono and stereo variants, we are limited to 2
+                * channels.
+                *
+                * The following code assumes for stereo controls the
+                * first path is the left channel, and all remaining
+                * paths are the right channel.
+                */
+               if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
+                       if (reg != mc->rreg)
+                               soc_dapm_read(p->sink->dapm, mc->rreg, &val);
+                       val = (val >> mc->rshift) & mask;
+               } else {
+                       val = (val >> shift) & mask;
+               }
                if (invert)
                        val = max - val;
                p->connect = !!val;
@@ -749,13 +773,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
 static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_path *path, const char *control_name)
 {
-       int i;
+       int i, nth_path = 0;
 
        /* search for mixer kcontrol */
        for (i = 0; i < path->sink->num_kcontrols; i++) {
                if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
                        path->name = path->sink->kcontrol_news[i].name;
-                       dapm_set_mixer_path_status(path, i);
+                       dapm_set_mixer_path_status(path, i, nth_path++);
                        return 0;
                }
        }
@@ -1626,6 +1650,15 @@ static void dapm_widget_update(struct snd_soc_card *card)
                dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
                        w->name, ret);
 
+       if (update->has_second_set) {
+               ret = soc_dapm_update_bits(w->dapm, update->reg2,
+                                          update->mask2, update->val2);
+               if (ret < 0)
+                       dev_err(w->dapm->dev,
+                               "ASoC: %s DAPM update failed: %d\n",
+                               w->name, ret);
+       }
+
        for (wi = 0; wi < wlist->num_widgets; wi++) {
                w = wlist->widgets[wi];
 
@@ -2177,7 +2210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
 static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
-                                  struct snd_kcontrol *kcontrol, int connect)
+                                      struct snd_kcontrol *kcontrol,
+                                      int connect, int rconnect)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
@@ -2186,8 +2220,33 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
 
        /* find dapm widget path assoc with kcontrol */
        dapm_kcontrol_for_each_path(path, kcontrol) {
+               /*
+                * Ideally this function should support any number of
+                * paths and channels. But since kcontrols only come
+                * in mono and stereo variants, we are limited to 2
+                * channels.
+                *
+                * The following code assumes for stereo controls the
+                * first path (when 'found == 0') is the left channel,
+                * and all remaining paths (when 'found == 1') are the
+                * right channel.
+                *
+                * A stereo control is signified by a valid 'rconnect'
+                * value, either 0 for unconnected, or >= 0 for connected.
+                * This is chosen instead of using snd_soc_volsw_is_stereo,
+                * so that the behavior of snd_soc_dapm_mixer_update_power
+                * doesn't change even when the kcontrol passed in is
+                * stereo.
+                *
+                * It passes 'connect' as the path connect status for
+                * the left channel, and 'rconnect' for the right
+                * channel.
+                */
+               if (found && rconnect >= 0)
+                       soc_dapm_connect_path(path, rconnect, "mixer update");
+               else
+                       soc_dapm_connect_path(path, connect, "mixer update");
                found = 1;
-               soc_dapm_connect_path(path, connect, "mixer update");
        }
 
        if (found)
@@ -2205,7 +2264,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        card->update = update;
-       ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
+       ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
        card->update = NULL;
        mutex_unlock(&card->dapm_mutex);
        if (ret > 0)
@@ -3030,22 +3089,28 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        int reg = mc->reg;
        unsigned int shift = mc->shift;
        int max = mc->max;
+       unsigned int width = fls(max);
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
-       unsigned int val;
+       unsigned int reg_val, val, rval = 0;
        int ret = 0;
 
-       if (snd_soc_volsw_is_stereo(mc))
-               dev_warn(dapm->dev,
-                        "ASoC: Control '%s' is stereo, which is not supported\n",
-                        kcontrol->id.name);
-
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
-               ret = soc_dapm_read(dapm, reg, &val);
-               val = (val >> shift) & mask;
+               ret = soc_dapm_read(dapm, reg, &reg_val);
+               val = (reg_val >> shift) & mask;
+
+               if (ret == 0 && reg != mc->rreg)
+                       ret = soc_dapm_read(dapm, mc->rreg, &reg_val);
+
+               if (snd_soc_volsw_is_stereo(mc))
+                       rval = (reg_val >> mc->rshift) & mask;
        } else {
-               val = dapm_kcontrol_get_value(kcontrol);
+               reg_val = dapm_kcontrol_get_value(kcontrol);
+               val = reg_val & mask;
+
+               if (snd_soc_volsw_is_stereo(mc))
+                       rval = (reg_val >> width) & mask;
        }
        mutex_unlock(&card->dapm_mutex);
 
@@ -3057,6 +3122,13 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        else
                ucontrol->value.integer.value[0] = val;
 
+       if (snd_soc_volsw_is_stereo(mc)) {
+               if (invert)
+                       ucontrol->value.integer.value[1] = max - rval;
+               else
+                       ucontrol->value.integer.value[1] = rval;
+       }
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
@@ -3080,46 +3152,66 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        int reg = mc->reg;
        unsigned int shift = mc->shift;
        int max = mc->max;
-       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int width = fls(max);
+       unsigned int mask = (1 << width) - 1;
        unsigned int invert = mc->invert;
-       unsigned int val;
-       int connect, change, reg_change = 0;
-       struct snd_soc_dapm_update update;
+       unsigned int val, rval = 0;
+       int connect, rconnect = -1, change, reg_change = 0;
+       struct snd_soc_dapm_update update = { NULL };
        int ret = 0;
 
-       if (snd_soc_volsw_is_stereo(mc))
-               dev_warn(dapm->dev,
-                        "ASoC: Control '%s' is stereo, which is not supported\n",
-                        kcontrol->id.name);
-
        val = (ucontrol->value.integer.value[0] & mask);
        connect = !!val;
 
        if (invert)
                val = max - val;
 
+       if (snd_soc_volsw_is_stereo(mc)) {
+               rval = (ucontrol->value.integer.value[1] & mask);
+               rconnect = !!rval;
+               if (invert)
+                       rval = max - rval;
+       }
+
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = dapm_kcontrol_set_value(kcontrol, val);
+       /* This assumes field width < (bits in unsigned int / 2) */
+       if (width > sizeof(unsigned int) * 8 / 2)
+               dev_warn(dapm->dev,
+                        "ASoC: control %s field width limit exceeded\n",
+                        kcontrol->id.name);
+       change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
 
        if (reg != SND_SOC_NOPM) {
-               mask = mask << shift;
                val = val << shift;
+               rval = rval << mc->rshift;
+
+               reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
 
-               reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
+               if (snd_soc_volsw_is_stereo(mc))
+                       reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
+                                                        mask << mc->rshift,
+                                                        rval);
        }
 
        if (change || reg_change) {
                if (reg_change) {
+                       if (snd_soc_volsw_is_stereo(mc)) {
+                               update.has_second_set = true;
+                               update.reg2 = mc->rreg;
+                               update.mask2 = mask << mc->rshift;
+                               update.val2 = rval;
+                       }
                        update.kcontrol = kcontrol;
                        update.reg = reg;
-                       update.mask = mask;
+                       update.mask = mask << shift;
                        update.val = val;
                        card->update = &update;
                }
                change |= reg_change;
 
-               ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
+               ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
+                                                 rconnect);
 
                card->update = NULL;
        }
@@ -3192,7 +3284,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        unsigned int *item = ucontrol->value.enumerated.item;
        unsigned int val, change, reg_change = 0;
        unsigned int mask;
-       struct snd_soc_dapm_update update;
+       struct snd_soc_dapm_update update = { NULL };
        int ret = 0;
 
        if (item[0] >= e->items)
index 6cef3977507ae15c11ff074c5e33c0b275cef9c8..17eb14935577764a59b9dd06e27cf515ce850ab8 100644 (file)
@@ -263,7 +263,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
        struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
        const struct snd_dmaengine_pcm_config *config = pcm->config;
        struct device *dev = rtd->platform->dev;
-       struct snd_dmaengine_dai_dma_data *dma_data;
        struct snd_pcm_substream *substream;
        size_t prealloc_buffer_size;
        size_t max_buffer_size;
@@ -278,19 +277,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
                max_buffer_size = SIZE_MAX;
        }
 
-
        for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
                substream = rtd->pcm->streams[i].substream;
                if (!substream)
                        continue;
 
-               dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-               if (!pcm->chan[i] &&
-                   (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME))
-                       pcm->chan[i] = dma_request_slave_channel(dev,
-                               dma_data->chan_name);
-
                if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) {
                        pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd,
                                substream);
@@ -359,9 +350,7 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
        const char *name;
        struct dma_chan *chan;
 
-       if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT |
-                          SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) ||
-           !dev->of_node)
+       if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node)
                return 0;
 
        if (config && config->dma_dev) {
index d56a16a0f6fa41ff1930b3898e173bd4b7d3bfd8..e7a1eaa2772f4418534d094e576b424a76aaa844 100644 (file)
@@ -2882,7 +2882,7 @@ int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
 EXPORT_SYMBOL_GPL(snd_soc_platform_trigger);
 
 #ifdef CONFIG_DEBUG_FS
-static char *dpcm_state_string(enum snd_soc_dpcm_state state)
+static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
 {
        switch (state) {
        case SND_SOC_DPCM_STATE_NEW:
index 393e8f0fe2cc6902c4bfaf7a54519496c2d073a5..644d9a9ebfbc592f7fabf677bd8d721cee8b3196 100644 (file)
@@ -58,6 +58,205 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
 }
 EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
 
+int snd_soc_component_enable_pin(struct snd_soc_component *component,
+                                const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_enable_pin(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_enable_pin(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin);
+
+int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component,
+                                         const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_enable_pin_unlocked(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked);
+
+int snd_soc_component_disable_pin(struct snd_soc_component *component,
+                                 const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_disable_pin(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_disable_pin(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin);
+
+int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component,
+                                          const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_disable_pin_unlocked(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked);
+
+int snd_soc_component_nc_pin(struct snd_soc_component *component,
+                            const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_nc_pin(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_nc_pin(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin);
+
+int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component,
+                                     const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_nc_pin_unlocked(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked);
+
+int snd_soc_component_get_pin_status(struct snd_soc_component *component,
+                                    const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_get_pin_status(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_get_pin_status(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status);
+
+int snd_soc_component_force_enable_pin(struct snd_soc_component *component,
+                                      const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_force_enable_pin(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_force_enable_pin(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin);
+
+int snd_soc_component_force_enable_pin_unlocked(
+                                       struct snd_soc_component *component,
+                                       const char *pin)
+{
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
+       char *full_name;
+       int ret;
+
+       if (!component->name_prefix)
+               return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
+
+       full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin);
+       if (!full_name)
+               return -ENOMEM;
+
+       ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name);
+       kfree(full_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked);
+
 static const struct snd_pcm_hardware dummy_dma_hardware = {
        /* Random values to keep userspace happy when checking constraints */
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
index 1bc8ebc2528eb1bdf0c1df6832e943d8eebaa29f..ad54d4cf58ada992f6f279cc0e6a00386e8e273e 100644 (file)
@@ -614,7 +614,11 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
        iec958->status[3] = ucontrol->value.iec958.status[3];
        mutex_unlock(&player->ctrl_lock);
 
-       uni_player_set_channel_status(player, NULL);
+       if (player->substream && player->substream->runtime)
+               uni_player_set_channel_status(player,
+                                             player->substream->runtime);
+       else
+               uni_player_set_channel_status(player, NULL);
 
        return 0;
 }
index e047ec06d5382cd61e5ff4e56269b508e714ef59..56ed9472e89fe98c98f82b3b90ed61fdd2e774e4 100644 (file)
@@ -765,11 +765,11 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
 
        card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
        if (!card)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
        if (!card->dai_link)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        card->dev               = dev;
        card->name              = "sun4i-codec";
@@ -829,12 +829,6 @@ static int sun4i_codec_probe(struct platform_device *pdev)
                return PTR_ERR(scodec->clk_module);
        }
 
-       /* Enable the bus clock */
-       if (clk_prepare_enable(scodec->clk_apb)) {
-               dev_err(&pdev->dev, "Failed to enable the APB clock\n");
-               return -EINVAL;
-       }
-
        scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
                                                  GPIOD_OUT_LOW);
        if (IS_ERR(scodec->gpio_pa)) {
@@ -844,6 +838,12 @@ static int sun4i_codec_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* Enable the bus clock */
+       if (clk_prepare_enable(scodec->clk_apb)) {
+               dev_err(&pdev->dev, "Failed to enable the APB clock\n");
+               return -EINVAL;
+       }
+
        /* DMA configuration for TX FIFO */
        scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
        scodec->playback_dma_data.maxburst = 4;
@@ -876,7 +876,8 @@ static int sun4i_codec_probe(struct platform_device *pdev)
        }
 
        card = sun4i_codec_create_card(&pdev->dev);
-       if (!card) {
+       if (IS_ERR(card)) {
+               ret = PTR_ERR(card);
                dev_err(&pdev->dev, "Failed to create our card\n");
                goto err_unregister_codec;
        }
index 0190cb6332f2d9ff6570d2628442d402f8a1ab29..52063b2626677144d8f47585147cc129011f93c7 100644 (file)
@@ -304,7 +304,7 @@ struct snd_dbri {
        spinlock_t lock;
 
        struct dbri_dma *dma;   /* Pointer to our DMA block */
-       u32 dma_dvma;           /* DBRI visible DMA address */
+       dma_addr_t dma_dvma;    /* DBRI visible DMA address */
 
        void __iomem *regs;     /* dbri HW regs */
        int dbri_irqp;          /* intr queue pointer */
@@ -657,12 +657,14 @@ static void dbri_cmdwait(struct snd_dbri *dbri)
  */
 static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len)
 {
+       u32 dvma_addr = (u32)dbri->dma_dvma;
+
        /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */
        len += 2;
        spin_lock(&dbri->cmdlock);
        if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2)
                return dbri->cmdptr + 2;
-       else if (len < sbus_readl(dbri->regs + REG8) - dbri->dma_dvma)
+       else if (len < sbus_readl(dbri->regs + REG8) - dvma_addr)
                return dbri->dma->cmd;
        else
                printk(KERN_ERR "DBRI: no space for commands.");
@@ -680,6 +682,7 @@ static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len)
  */
 static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len)
 {
+       u32 dvma_addr = (u32)dbri->dma_dvma;
        s32 tmp, addr;
        static int wait_id = 0;
 
@@ -689,7 +692,7 @@ static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len)
        *(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id);
 
        /* Replace the last command with JUMP */
-       addr = dbri->dma_dvma + (cmd - len - dbri->dma->cmd) * sizeof(s32);
+       addr = dvma_addr + (cmd - len - dbri->dma->cmd) * sizeof(s32);
        *(dbri->cmdptr+1) = addr;
        *(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0);
 
@@ -747,6 +750,7 @@ static void dbri_reset(struct snd_dbri *dbri)
 /* Lock must not be held before calling this */
 static void dbri_initialize(struct snd_dbri *dbri)
 {
+       u32 dvma_addr = (u32)dbri->dma_dvma;
        s32 *cmd;
        u32 dma_addr;
        unsigned long flags;
@@ -764,7 +768,7 @@ static void dbri_initialize(struct snd_dbri *dbri)
        /*
         * Initialize the interrupt ring buffer.
         */
-       dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
+       dma_addr = dvma_addr + dbri_dma_off(intr, 0);
        dbri->dma->intr[0] = dma_addr;
        dbri->dbri_irqp = 1;
        /*
@@ -778,7 +782,7 @@ static void dbri_initialize(struct snd_dbri *dbri)
        dbri->cmdptr = cmd;
        *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
        *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
-       dma_addr = dbri->dma_dvma + dbri_dma_off(cmd, 0);
+       dma_addr = dvma_addr + dbri_dma_off(cmd, 0);
        sbus_writel(dma_addr, dbri->regs + REG8);
        spin_unlock(&dbri->cmdlock);
 
@@ -1077,6 +1081,7 @@ static void recv_fixed(struct snd_dbri *dbri, int pipe, volatile __u32 *ptr)
 static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period)
 {
        struct dbri_streaminfo *info = &dbri->stream_info[streamno];
+       u32 dvma_addr = (u32)dbri->dma_dvma;
        __u32 dvma_buffer;
        int desc;
        int len;
@@ -1177,7 +1182,7 @@ static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period)
                else {
                        dbri->next_desc[last_desc] = desc;
                        dbri->dma->desc[last_desc].nda =
-                           dbri->dma_dvma + dbri_dma_off(desc, desc);
+                           dvma_addr + dbri_dma_off(desc, desc);
                }
 
                last_desc = desc;
@@ -1192,7 +1197,7 @@ static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period)
        }
 
        dbri->dma->desc[last_desc].nda =
-           dbri->dma_dvma + dbri_dma_off(desc, first_desc);
+           dvma_addr + dbri_dma_off(desc, first_desc);
        dbri->next_desc[last_desc] = first_desc;
        dbri->pipes[info->pipe].first_desc = first_desc;
        dbri->pipes[info->pipe].desc = first_desc;
@@ -1697,6 +1702,7 @@ interrupts are disabled.
 static void xmit_descs(struct snd_dbri *dbri)
 {
        struct dbri_streaminfo *info;
+       u32 dvma_addr;
        s32 *cmd;
        unsigned long flags;
        int first_td;
@@ -1704,6 +1710,7 @@ static void xmit_descs(struct snd_dbri *dbri)
        if (dbri == NULL)
                return;         /* Disabled */
 
+       dvma_addr = (u32)dbri->dma_dvma;
        info = &dbri->stream_info[DBRI_REC];
        spin_lock_irqsave(&dbri->lock, flags);
 
@@ -1718,7 +1725,7 @@ static void xmit_descs(struct snd_dbri *dbri)
                        *(cmd++) = DBRI_CMD(D_SDP, 0,
                                            dbri->pipes[info->pipe].sdp
                                            | D_SDP_P | D_SDP_EVERY | D_SDP_C);
-                       *(cmd++) = dbri->dma_dvma +
+                       *(cmd++) = dvma_addr +
                                   dbri_dma_off(desc, first_td);
                        dbri_cmdsend(dbri, cmd, 2);
 
@@ -1740,7 +1747,7 @@ static void xmit_descs(struct snd_dbri *dbri)
                        *(cmd++) = DBRI_CMD(D_SDP, 0,
                                            dbri->pipes[info->pipe].sdp
                                            | D_SDP_P | D_SDP_EVERY | D_SDP_C);
-                       *(cmd++) = dbri->dma_dvma +
+                       *(cmd++) = dvma_addr +
                                   dbri_dma_off(desc, first_td);
                        dbri_cmdsend(dbri, cmd, 2);
 
@@ -2539,7 +2546,7 @@ static int snd_dbri_create(struct snd_card *card,
        if (!dbri->dma)
                return -ENOMEM;
 
-       dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n",
+       dprintk(D_GEN, "DMA Cmd Block 0x%p (%pad)\n",
                dbri->dma, dbri->dma_dvma);
 
        /* Map the registers into memory. */
index 9e5276d6dda05c999fcba24ff35ab7345513c6da..2ddc034673a8e99d232ebe62b87ff4115628d453 100644 (file)
@@ -315,7 +315,8 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip)
                snd_usb_endpoint_free(ep);
 
        mutex_destroy(&chip->mutex);
-       dev_set_drvdata(&chip->dev->dev, NULL);
+       if (!atomic_read(&chip->shutdown))
+               dev_set_drvdata(&chip->dev->dev, NULL);
        kfree(chip);
        return 0;
 }
index c60a776e815d72f14b9b6345f2e8a0266f8ec1b6..8a59d4782a0f4d3c33b3e6840cbe265ba8ee4406 100644 (file)
@@ -2907,6 +2907,23 @@ AU0828_DEVICE(0x2040, 0x7260, "Hauppauge", "HVR-950Q"),
 AU0828_DEVICE(0x2040, 0x7213, "Hauppauge", "HVR-950Q"),
 AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
 
+/* Syntek STK1160 */
+{
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .idVendor = 0x05e1,
+       .idProduct = 0x0408,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Syntek",
+               .product_name = "STK1160",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUDIO_ALIGN_TRANSFER
+       }
+},
+
 /* Digidesign Mbox */
 {
        /* Thanks to Clemens Ladisch <clemens@ladisch.de> */
index 1188bc849ee3b3253fd8229fca21bf2d6c87856e..a39629206864e5bb74aaddea15ca1ab762877042 100644 (file)
 #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 
 #define X86_FEATURE_INTEL_PT   ( 7*32+15) /* Intel Processor Trace */
+#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
+#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
index c0c0b265e88e54b868858a812839c4c24979651e..5e0dea2cdc01f65849f49f10392293a21b3a468d 100644 (file)
@@ -98,6 +98,15 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
                        *type = INSN_FP_SETUP;
                break;
 
+       case 0x8d:
+               if (insn.rex_prefix.nbytes &&
+                   insn.rex_prefix.bytes[0] == 0x48 &&
+                   insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c &&
+                   insn.sib.nbytes && insn.sib.bytes[0] == 0x24)
+                       /* lea %(rsp), %rbp */
+                       *type = INSN_FP_SETUP;
+               break;
+
        case 0x90:
                *type = INSN_NOP;
                break;
index 143b6cdd7f068f88fa8487aba804621c37523211..e8a1f699058a29ba695bfbf24781562c665e4525 100644 (file)
@@ -97,6 +97,19 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file,
        return next;
 }
 
+static bool gcov_enabled(struct objtool_file *file)
+{
+       struct section *sec;
+       struct symbol *sym;
+
+       list_for_each_entry(sec, &file->elf->sections, list)
+               list_for_each_entry(sym, &sec->symbol_list, list)
+                       if (!strncmp(sym->name, "__gcov_.", 8))
+                               return true;
+
+       return false;
+}
+
 #define for_each_insn(file, insn)                                      \
        list_for_each_entry(insn, &file->insn_list, list)
 
@@ -713,6 +726,7 @@ static struct rela *find_switch_table(struct objtool_file *file,
                                      struct instruction *insn)
 {
        struct rela *text_rela, *rodata_rela;
+       struct instruction *orig_insn = insn;
 
        text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
        if (text_rela && text_rela->sym == file->rodata->sym) {
@@ -733,10 +747,16 @@ static struct rela *find_switch_table(struct objtool_file *file,
 
        /* case 3 */
        func_for_each_insn_continue_reverse(file, func, insn) {
-               if (insn->type == INSN_JUMP_UNCONDITIONAL ||
-                   insn->type == INSN_JUMP_DYNAMIC)
+               if (insn->type == INSN_JUMP_DYNAMIC)
                        break;
 
+               /* allow small jumps within the range */
+               if (insn->type == INSN_JUMP_UNCONDITIONAL &&
+                   insn->jump_dest &&
+                   (insn->jump_dest->offset <= insn->offset ||
+                    insn->jump_dest->offset > orig_insn->offset))
+                   break;
+
                text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
                                                    insn->len);
                if (text_rela && text_rela->sym == file->rodata->sym)
@@ -1034,34 +1054,6 @@ static int validate_branch(struct objtool_file *file,
        return 0;
 }
 
-static bool is_gcov_insn(struct instruction *insn)
-{
-       struct rela *rela;
-       struct section *sec;
-       struct symbol *sym;
-       unsigned long offset;
-
-       rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
-       if (!rela)
-               return false;
-
-       if (rela->sym->type != STT_SECTION)
-               return false;
-
-       sec = rela->sym->sec;
-       offset = rela->addend + insn->offset + insn->len - rela->offset;
-
-       list_for_each_entry(sym, &sec->symbol_list, list) {
-               if (sym->type != STT_OBJECT)
-                       continue;
-
-               if (offset >= sym->offset && offset < sym->offset + sym->len)
-                       return (!memcmp(sym->name, "__gcov0.", 8));
-       }
-
-       return false;
-}
-
 static bool is_kasan_insn(struct instruction *insn)
 {
        return (insn->type == INSN_CALL &&
@@ -1083,9 +1075,6 @@ static bool ignore_unreachable_insn(struct symbol *func,
        if (insn->type == INSN_NOP)
                return true;
 
-       if (is_gcov_insn(insn))
-               return true;
-
        /*
         * Check if this (or a subsequent) instruction is related to
         * CONFIG_UBSAN or CONFIG_KASAN.
@@ -1146,6 +1135,19 @@ static int validate_functions(struct objtool_file *file)
                                    ignore_unreachable_insn(func, insn))
                                        continue;
 
+                               /*
+                                * gcov produces a lot of unreachable
+                                * instructions.  If we get an unreachable
+                                * warning and the file has gcov enabled, just
+                                * ignore it, and all other such warnings for
+                                * the file.
+                                */
+                               if (!file->ignore_unreachables &&
+                                   gcov_enabled(file)) {
+                                       file->ignore_unreachables = true;
+                                       continue;
+                               }
+
                                WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset);
                                warnings++;
                        }
index 5ce61a1bda9ca863cbcd4c327f2abd8f621bf1f6..df14e6b67b63b781846d71b80cbc6e8ee1edc0e3 100644 (file)
@@ -36,7 +36,7 @@ SOLIBEXT=so
 # The following works at least on fedora 23, you may need the next
 # line for other distros.
 ifneq (,$(wildcard /usr/sbin/update-java-alternatives))
-JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
+JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}')
 else
   ifneq (,$(wildcard /usr/sbin/alternatives))
     JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
index fb8e42c7507add43bc9c1848cf3ef300382ee313..a53fef0c673bbbfcf8669ffb66f5de079dbc7e18 100644 (file)
@@ -601,7 +601,8 @@ int hist_browser__run(struct hist_browser *browser, const char *help)
                        u64 nr_entries;
                        hbt->timer(hbt->arg);
 
-                       if (hist_browser__has_filter(browser))
+                       if (hist_browser__has_filter(browser) ||
+                           symbol_conf.report_hierarchy)
                                hist_browser__update_nr_entries(browser);
 
                        nr_entries = hist_browser__nr_entries(browser);
@@ -1336,8 +1337,8 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
                }
 
                if (first) {
-                       ui_browser__printf(&browser->b, "%c", folded_sign);
-                       width--;
+                       ui_browser__printf(&browser->b, "%c ", folded_sign);
+                       width -= 2;
                        first = false;
                } else {
                        ui_browser__printf(&browser->b, "  ");
@@ -1360,8 +1361,10 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
                width -= hpp.buf - s;
        }
 
-       ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
-       width -= hierarchy_indent;
+       if (!first) {
+               ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
+               width -= hierarchy_indent;
+       }
 
        if (column >= browser->b.horiz_scroll) {
                char s[2048];
@@ -1380,7 +1383,13 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
                }
 
                perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
-                       ui_browser__write_nstring(&browser->b, "", 2);
+                       if (first) {
+                               ui_browser__printf(&browser->b, "%c ", folded_sign);
+                               first = false;
+                       } else {
+                               ui_browser__write_nstring(&browser->b, "", 2);
+                       }
+
                        width -= 2;
 
                        /*
@@ -1554,10 +1563,11 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
        int indent = hists->nr_hpp_node - 2;
        bool first_node, first_col;
 
-       ret = scnprintf(buf, size, " ");
+       ret = scnprintf(buf, size, "  ");
        if (advance_hpp_check(&dummy_hpp, ret))
                return ret;
 
+       first_node = true;
        /* the first hpp_list_node is for overhead columns */
        fmt_node = list_first_entry(&hists->hpp_formats,
                                    struct perf_hpp_list_node, list);
@@ -1572,12 +1582,16 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
                ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
+
+               first_node = false;
        }
 
-       ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
-                       indent * HIERARCHY_INDENT, "");
-       if (advance_hpp_check(&dummy_hpp, ret))
-               return ret;
+       if (!first_node) {
+               ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
+                               indent * HIERARCHY_INDENT, "");
+               if (advance_hpp_check(&dummy_hpp, ret))
+                       return ret;
+       }
 
        first_node = true;
        list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
@@ -2075,8 +2089,21 @@ void hist_browser__init(struct hist_browser *browser,
        browser->b.use_navkeypressed    = true;
        browser->show_headers           = symbol_conf.show_hist_headers;
 
-       hists__for_each_format(hists, fmt)
+       if (symbol_conf.report_hierarchy) {
+               struct perf_hpp_list_node *fmt_node;
+
+               /* count overhead columns (in the first node) */
+               fmt_node = list_first_entry(&hists->hpp_formats,
+                                           struct perf_hpp_list_node, list);
+               perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
+                       ++browser->b.columns;
+
+               /* add a single column for whole hierarchy sort keys*/
                ++browser->b.columns;
+       } else {
+               hists__for_each_format(hists, fmt)
+                       ++browser->b.columns;
+       }
 
        hists__reset_column_width(hists);
 }
index 85dd0db0a127995a725eade74a12e5da8569b80c..2f3eded54b0cc65a6d2ac59456a2acf2d7921059 100644 (file)
@@ -1895,7 +1895,6 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
        if (ph->needs_swap)
                nr = bswap_32(nr);
 
-       ph->env.nr_numa_nodes = nr;
        nodes = zalloc(sizeof(*nodes) * nr);
        if (!nodes)
                return -ENOMEM;
@@ -1932,6 +1931,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
 
                free(str);
        }
+       ph->env.nr_numa_nodes = nr;
        ph->env.numa_nodes = nodes;
        return 0;
 
index b02992efb51383c06ce507adcba261100e101dd8..a69f027368ef49caf0c259e035cf886fb7062d32 100644 (file)
@@ -1600,18 +1600,18 @@ static void hists__hierarchy_output_resort(struct hists *hists,
                if (prog)
                        ui_progress__update(prog, 1);
 
+               hists->nr_entries++;
+               if (!he->filtered) {
+                       hists->nr_non_filtered_entries++;
+                       hists__calc_col_len(hists, he);
+               }
+
                if (!he->leaf) {
                        hists__hierarchy_output_resort(hists, prog,
                                                       &he->hroot_in,
                                                       &he->hroot_out,
                                                       min_callchain_hits,
                                                       use_callchain);
-                       hists->nr_entries++;
-                       if (!he->filtered) {
-                               hists->nr_non_filtered_entries++;
-                               hists__calc_col_len(hists, he);
-                       }
-
                        continue;
                }
 
index 9f43fda2570f959833c85b89aa29b3612c6d6abb..660fca05bc93bd8f724a9f3cef3f0f3d86abb983 100644 (file)
@@ -136,8 +136,8 @@ do {                                                        \
 group          [^,{}/]*[{][^}]*[}][^,{}/]*
 event_pmu      [^,{}/]+[/][^/]*[/][^,{}/]*
 event          [^,{}/]+
-bpf_object     .*\.(o|bpf)
-bpf_source     .*\.c
+bpf_object     [^,{}]+\.(o|bpf)
+bpf_source     [^,{}]+\.c
 
 num_dec                [0-9]+
 num_hex                0x[a-fA-F0-9]+
index a538ff44b108952dbe25363abea8f34810211fb6..a1883bbb014478d9239d24fda259c61bde853b23 100644 (file)
@@ -8,18 +8,19 @@
 # as published by the Free Software Foundation; version 2
 # of the License.
 
-include ../../../../scripts/Makefile.include
-
-OUTPUT=./
-ifeq ("$(origin O)", "command line")
-       OUTPUT := $(O)/
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
 endif
 
-ifneq ($(OUTPUT),)
-# check that the output directory actually exists
-OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
-$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
+include $(srctree)/../../scripts/Makefile.include
+
+OUTPUT=$(srctree)/
+ifeq ("$(origin O)", "command line")
+       OUTPUT := $(O)/power/acpi/
 endif
+#$(info Determined 'OUTPUT' to be $(OUTPUT))
 
 # --- CONFIGURATION BEGIN ---
 
@@ -70,8 +71,8 @@ WARNINGS := -Wall
 WARNINGS += $(call cc-supports,-Wstrict-prototypes)
 WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
 
-KERNEL_INCLUDE := ../../../include
-ACPICA_INCLUDE := ../../../drivers/acpi/acpica
+KERNEL_INCLUDE := $(OUTPUT)include
+ACPICA_INCLUDE := $(srctree)/../../../drivers/acpi/acpica
 CFLAGS += -D_LINUX -I$(KERNEL_INCLUDE) -I$(ACPICA_INCLUDE)
 CFLAGS += $(WARNINGS)
 
index ec87a9e562c0ea0cd08c0cee096850e28f8615e9..373738338f5186199e8e97164eb1ae0a3ce33966 100644 (file)
@@ -8,28 +8,42 @@
 # as published by the Free Software Foundation; version 2
 # of the License.
 
-$(OUTPUT)$(TOOL): $(TOOL_OBJS) FORCE
-       $(ECHO) "  LD      " $@
-       $(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $(TOOL_OBJS) -L$(OUTPUT) -o $@
+objdir := $(OUTPUT)tools/$(TOOL)/
+toolobjs := $(addprefix $(objdir),$(TOOL_OBJS))
+$(OUTPUT)$(TOOL): $(toolobjs) FORCE
+       $(ECHO) "  LD      " $(subst $(OUTPUT),,$@)
+       $(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $(toolobjs) -L$(OUTPUT) -o $@
+       $(ECHO) "  STRIP   " $(subst $(OUTPUT),,$@)
        $(QUIET) $(STRIPCMD) $@
 
-$(OUTPUT)%.o: %.c
-       $(ECHO) "  CC      " $@
+$(KERNEL_INCLUDE):
+       $(ECHO) "  MKDIR   " $(subst $(OUTPUT),,$@)
+       $(QUIET) mkdir -p $(KERNEL_INCLUDE)
+       $(ECHO) "  CP      " $(subst $(OUTPUT),,$@)
+       $(QUIET) cp -rf $(srctree)/../../../include/acpi $(KERNEL_INCLUDE)/
+
+$(objdir)%.o: %.c $(KERNEL_INCLUDE)
+       $(ECHO) "  CC      " $(subst $(OUTPUT),,$@)
        $(QUIET) $(CC) -c $(CFLAGS) -o $@ $<
 
 all: $(OUTPUT)$(TOOL)
 clean:
-       -find $(OUTPUT) \( -not -type d \) \
-       -and \( -name '*~' -o -name '*.[oas]' \) \
-       -type f -print \
-        | xargs rm -f
-       -rm -f $(OUTPUT)$(TOOL)
+       $(ECHO) "  RMOBJ   " $(subst $(OUTPUT),,$(objdir))
+       $(QUIET) find $(objdir) \( -not -type d \)\
+                -and \( -name '*~' -o -name '*.[oas]' \)\
+                -type f -print | xargs rm -f
+       $(ECHO) "  RM      " $(TOOL)
+       $(QUIET) rm -f $(OUTPUT)$(TOOL)
+       $(ECHO) "  RMINC   " $(subst $(OUTPUT),,$(KERNEL_INCLUDE))
+       $(QUIET) rm -rf $(KERNEL_INCLUDE)
 
 install-tools:
-       $(INSTALL) -d $(DESTDIR)${sbindir}
-       $(INSTALL_PROGRAM) $(OUTPUT)$(TOOL) $(DESTDIR)${sbindir}
+       $(ECHO) "  INST    " $(TOOL)
+       $(QUIET) $(INSTALL) -d $(DESTDIR)$(sbindir)
+       $(QUIET) $(INSTALL_PROGRAM) $(OUTPUT)$(TOOL) $(DESTDIR)$(sbindir)
 uninstall-tools:
-       - rm -f $(DESTDIR)${sbindir}/$(TOOL)
+       $(ECHO) "  UNINST  " $(TOOL)
+       $(QUIET) rm -f $(DESTDIR)$(sbindir)/$(TOOL)
 
 install: all install-tools $(EXTRA_INSTALL)
 uninstall: uninstall-tools $(EXTRA_UNINSTALL)
index 352df4b41ae9ecdff1f938be6e3f28b2f53fa5c3..f2d06e773eb4fea8f2d5ea4aae91e06afbcabcf8 100644 (file)
@@ -17,9 +17,7 @@ vpath %.c \
        ../../os_specific/service_layers\
        .
 CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\
-       -I.\
-       -I../../../../../drivers/acpi/acpica\
-       -I../../../../../include
+       -I.
 LDFLAGS += -lpthread
 TOOL_OBJS = \
        acpidbg.o
index a88ac45b7756aedc77099ca5adbc1de268d5c33c..4308362d7068eb346931aa7eda7a8d4c769af35e 100644 (file)
 #include <acpi/acpi.h>
 
 /* Headers not included by include/acpi/platform/aclinux.h */
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
 #include <stdbool.h>
 #include <fcntl.h>
 #include <assert.h>
-#include <linux/circ_buf.h>
+#include <sys/select.h>
+#include "../../../../../include/linux/circ_buf.h"
 
 #define ACPI_AML_FILE          "/sys/kernel/debug/acpi/acpidbg"
 #define ACPI_AML_SEC_TICK      1
index 04b5db7c7c0bd0608c8601a46766e551bb021e66..f7c7af1f9258b08ec2eb4f1c01a63184ea217b95 100644 (file)
@@ -19,9 +19,7 @@ vpath %.c \
        ./\
        ../../common\
        ../../os_specific/service_layers
-CFLAGS += -DACPI_DUMP_APP -I.\
-       -I../../../../../drivers/acpi/acpica\
-       -I../../../../../include
+CFLAGS += -DACPI_DUMP_APP -I.
 TOOL_OBJS = \
        apdump.o\
        apfiles.o\
@@ -49,7 +47,9 @@ TOOL_OBJS = \
 
 include ../../Makefile.rules
 
-install-man: ../../man/acpidump.8
-       $(INSTALL_DATA) -D $< $(DESTDIR)${mandir}/man8/acpidump.8
+install-man: $(srctree)/man/acpidump.8
+       $(ECHO) "  INST    " acpidump.8
+       $(QUIET) $(INSTALL_DATA) -D $< $(DESTDIR)$(mandir)/man8/acpidump.8
 uninstall-man:
-       - rm -f $(DESTDIR)${mandir}/man8/acpidump.8
+       $(ECHO) "  UNINST  " acpidump.8
+       $(QUIET) rm -f $(DESTDIR)$(mandir)/man8/acpidump.8
index b4bf76971dc975c5232b96f27f56310f65d2bcdd..1eef0aed64239509795229d522cada4e80edf5a2 100644 (file)
@@ -296,7 +296,7 @@ int cmd_freq_set(int argc, char **argv)
                        struct cpufreq_affected_cpus *cpus;
 
                        if (!bitmask_isbitset(cpus_chosen, cpu) ||
-                           cpupower_is_cpu_online(cpu))
+                           cpupower_is_cpu_online(cpu) != 1)
                                continue;
 
                        cpus = cpufreq_get_related_cpus(cpu);
@@ -316,10 +316,7 @@ int cmd_freq_set(int argc, char **argv)
             cpu <= bitmask_last(cpus_chosen); cpu++) {
 
                if (!bitmask_isbitset(cpus_chosen, cpu) ||
-                   cpupower_is_cpu_online(cpu))
-                       continue;
-
-               if (cpupower_is_cpu_online(cpu) != 1)
+                   cpupower_is_cpu_online(cpu) != 1)
                        continue;
 
                printf(_("Setting cpu: %d\n"), cpu);
index 582db95127ed41cd5491562613a70ca7623bd190..405212be044a93f77db540eb0ee6d7ba4a62e825 100644 (file)
@@ -14,6 +14,7 @@ ldflags-y += --wrap=devm_memremap_pages
 ldflags-y += --wrap=insert_resource
 ldflags-y += --wrap=remove_resource
 ldflags-y += --wrap=acpi_evaluate_object
+ldflags-y += --wrap=acpi_evaluate_dsm
 
 DRIVERS := ../../../drivers
 NVDIMM_SRC := $(DRIVERS)/nvdimm
index 3ccef732fce9ac67d5012899690149fcc9c8ed47..64cae1a5deff956637a05b08c25565fe1718611b 100644 (file)
@@ -26,14 +26,17 @@ static LIST_HEAD(iomap_head);
 
 static struct iomap_ops {
        nfit_test_lookup_fn nfit_test_lookup;
+       nfit_test_evaluate_dsm_fn evaluate_dsm;
        struct list_head list;
 } iomap_ops = {
        .list = LIST_HEAD_INIT(iomap_ops.list),
 };
 
-void nfit_test_setup(nfit_test_lookup_fn lookup)
+void nfit_test_setup(nfit_test_lookup_fn lookup,
+               nfit_test_evaluate_dsm_fn evaluate)
 {
        iomap_ops.nfit_test_lookup = lookup;
+       iomap_ops.evaluate_dsm = evaluate;
        list_add_rcu(&iomap_ops.list, &iomap_head);
 }
 EXPORT_SYMBOL(nfit_test_setup);
@@ -367,4 +370,22 @@ acpi_status __wrap_acpi_evaluate_object(acpi_handle handle, acpi_string path,
 }
 EXPORT_SYMBOL(__wrap_acpi_evaluate_object);
 
+union acpi_object * __wrap_acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid,
+               u64 rev, u64 func, union acpi_object *argv4)
+{
+       union acpi_object *obj = ERR_PTR(-ENXIO);
+       struct iomap_ops *ops;
+
+       rcu_read_lock();
+       ops = list_first_or_null_rcu(&iomap_head, typeof(*ops), list);
+       if (ops)
+               obj = ops->evaluate_dsm(handle, uuid, rev, func, argv4);
+       rcu_read_unlock();
+
+       if (IS_ERR(obj))
+               return acpi_evaluate_dsm(handle, uuid, rev, func, argv4);
+       return obj;
+}
+EXPORT_SYMBOL(__wrap_acpi_evaluate_dsm);
+
 MODULE_LICENSE("GPL v2");
index c9a6458cb63e7514494811305fe8f41c1d3e6622..71620fa959530211c6c73c25ab71aaaba7cfa50a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sizes.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <nd-core.h>
 #include <nfit.h>
 #include <nd.h>
 #include "nfit_test.h"
@@ -1506,6 +1507,225 @@ static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa,
        return 0;
 }
 
+static unsigned long nfit_ctl_handle;
+
+union acpi_object *result;
+
+static union acpi_object *nfit_test_evaluate_dsm(acpi_handle handle,
+               const u8 *uuid, u64 rev, u64 func, union acpi_object *argv4)
+{
+       if (handle != &nfit_ctl_handle)
+               return ERR_PTR(-ENXIO);
+
+       return result;
+}
+
+static int setup_result(void *buf, size_t size)
+{
+       result = kmalloc(sizeof(union acpi_object) + size, GFP_KERNEL);
+       if (!result)
+               return -ENOMEM;
+       result->package.type = ACPI_TYPE_BUFFER,
+       result->buffer.pointer = (void *) (result + 1);
+       result->buffer.length = size;
+       memcpy(result->buffer.pointer, buf, size);
+       memset(buf, 0, size);
+       return 0;
+}
+
+static int nfit_ctl_test(struct device *dev)
+{
+       int rc, cmd_rc;
+       struct nvdimm *nvdimm;
+       struct acpi_device *adev;
+       struct nfit_mem *nfit_mem;
+       struct nd_ars_record *record;
+       struct acpi_nfit_desc *acpi_desc;
+       const u64 test_val = 0x0123456789abcdefULL;
+       unsigned long mask, cmd_size, offset;
+       union {
+               struct nd_cmd_get_config_size cfg_size;
+               struct nd_cmd_ars_status ars_stat;
+               struct nd_cmd_ars_cap ars_cap;
+               char buf[sizeof(struct nd_cmd_ars_status)
+                       + sizeof(struct nd_ars_record)];
+       } cmds;
+
+       adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL);
+       if (!adev)
+               return -ENOMEM;
+       *adev = (struct acpi_device) {
+               .handle = &nfit_ctl_handle,
+               .dev = {
+                       .init_name = "test-adev",
+               },
+       };
+
+       acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
+       if (!acpi_desc)
+               return -ENOMEM;
+       *acpi_desc = (struct acpi_nfit_desc) {
+               .nd_desc = {
+                       .cmd_mask = 1UL << ND_CMD_ARS_CAP
+                               | 1UL << ND_CMD_ARS_START
+                               | 1UL << ND_CMD_ARS_STATUS
+                               | 1UL << ND_CMD_CLEAR_ERROR,
+                       .module = THIS_MODULE,
+                       .provider_name = "ACPI.NFIT",
+                       .ndctl = acpi_nfit_ctl,
+               },
+               .dev = &adev->dev,
+       };
+
+       nfit_mem = devm_kzalloc(dev, sizeof(*nfit_mem), GFP_KERNEL);
+       if (!nfit_mem)
+               return -ENOMEM;
+
+       mask = 1UL << ND_CMD_SMART | 1UL << ND_CMD_SMART_THRESHOLD
+               | 1UL << ND_CMD_DIMM_FLAGS | 1UL << ND_CMD_GET_CONFIG_SIZE
+               | 1UL << ND_CMD_GET_CONFIG_DATA | 1UL << ND_CMD_SET_CONFIG_DATA
+               | 1UL << ND_CMD_VENDOR;
+       *nfit_mem = (struct nfit_mem) {
+               .adev = adev,
+               .family = NVDIMM_FAMILY_INTEL,
+               .dsm_mask = mask,
+       };
+
+       nvdimm = devm_kzalloc(dev, sizeof(*nvdimm), GFP_KERNEL);
+       if (!nvdimm)
+               return -ENOMEM;
+       *nvdimm = (struct nvdimm) {
+               .provider_data = nfit_mem,
+               .cmd_mask = mask,
+               .dev = {
+                       .init_name = "test-dimm",
+               },
+       };
+
+
+       /* basic checkout of a typical 'get config size' command */
+       cmd_size = sizeof(cmds.cfg_size);
+       cmds.cfg_size = (struct nd_cmd_get_config_size) {
+               .status = 0,
+               .config_size = SZ_128K,
+               .max_xfer = SZ_4K,
+       };
+       rc = setup_result(cmds.buf, cmd_size);
+       if (rc)
+               return rc;
+       rc = acpi_nfit_ctl(&acpi_desc->nd_desc, nvdimm, ND_CMD_GET_CONFIG_SIZE,
+                       cmds.buf, cmd_size, &cmd_rc);
+
+       if (rc < 0 || cmd_rc || cmds.cfg_size.status != 0
+                       || cmds.cfg_size.config_size != SZ_128K
+                       || cmds.cfg_size.max_xfer != SZ_4K) {
+               dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
+                               __func__, __LINE__, rc, cmd_rc);
+               return -EIO;
+       }
+
+
+       /* test ars_status with zero output */
+       cmd_size = offsetof(struct nd_cmd_ars_status, address);
+       cmds.ars_stat = (struct nd_cmd_ars_status) {
+               .out_length = 0,
+       };
+       rc = setup_result(cmds.buf, cmd_size);
+       if (rc)
+               return rc;
+       rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_STATUS,
+                       cmds.buf, cmd_size, &cmd_rc);
+
+       if (rc < 0 || cmd_rc) {
+               dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
+                               __func__, __LINE__, rc, cmd_rc);
+               return -EIO;
+       }
+
+
+       /* test ars_cap with benign extended status */
+       cmd_size = sizeof(cmds.ars_cap);
+       cmds.ars_cap = (struct nd_cmd_ars_cap) {
+               .status = ND_ARS_PERSISTENT << 16,
+       };
+       offset = offsetof(struct nd_cmd_ars_cap, status);
+       rc = setup_result(cmds.buf + offset, cmd_size - offset);
+       if (rc)
+               return rc;
+       rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_CAP,
+                       cmds.buf, cmd_size, &cmd_rc);
+
+       if (rc < 0 || cmd_rc) {
+               dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
+                               __func__, __LINE__, rc, cmd_rc);
+               return -EIO;
+       }
+
+
+       /* test ars_status with 'status' trimmed from 'out_length' */
+       cmd_size = sizeof(cmds.ars_stat) + sizeof(struct nd_ars_record);
+       cmds.ars_stat = (struct nd_cmd_ars_status) {
+               .out_length = cmd_size - 4,
+       };
+       record = &cmds.ars_stat.records[0];
+       *record = (struct nd_ars_record) {
+               .length = test_val,
+       };
+       rc = setup_result(cmds.buf, cmd_size);
+       if (rc)
+               return rc;
+       rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_STATUS,
+                       cmds.buf, cmd_size, &cmd_rc);
+
+       if (rc < 0 || cmd_rc || record->length != test_val) {
+               dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
+                               __func__, __LINE__, rc, cmd_rc);
+               return -EIO;
+       }
+
+
+       /* test ars_status with 'Output (Size)' including 'status' */
+       cmd_size = sizeof(cmds.ars_stat) + sizeof(struct nd_ars_record);
+       cmds.ars_stat = (struct nd_cmd_ars_status) {
+               .out_length = cmd_size,
+       };
+       record = &cmds.ars_stat.records[0];
+       *record = (struct nd_ars_record) {
+               .length = test_val,
+       };
+       rc = setup_result(cmds.buf, cmd_size);
+       if (rc)
+               return rc;
+       rc = acpi_nfit_ctl(&acpi_desc->nd_desc, NULL, ND_CMD_ARS_STATUS,
+                       cmds.buf, cmd_size, &cmd_rc);
+
+       if (rc < 0 || cmd_rc || record->length != test_val) {
+               dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
+                               __func__, __LINE__, rc, cmd_rc);
+               return -EIO;
+       }
+
+
+       /* test extended status for get_config_size results in failure */
+       cmd_size = sizeof(cmds.cfg_size);
+       cmds.cfg_size = (struct nd_cmd_get_config_size) {
+               .status = 1 << 16,
+       };
+       rc = setup_result(cmds.buf, cmd_size);
+       if (rc)
+               return rc;
+       rc = acpi_nfit_ctl(&acpi_desc->nd_desc, nvdimm, ND_CMD_GET_CONFIG_SIZE,
+                       cmds.buf, cmd_size, &cmd_rc);
+
+       if (rc < 0 || cmd_rc >= 0) {
+               dev_dbg(dev, "%s: failed at: %d rc: %d cmd_rc: %d\n",
+                               __func__, __LINE__, rc, cmd_rc);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static int nfit_test_probe(struct platform_device *pdev)
 {
        struct nvdimm_bus_descriptor *nd_desc;
@@ -1516,6 +1736,12 @@ static int nfit_test_probe(struct platform_device *pdev)
        union acpi_object *obj;
        int rc;
 
+       if (strcmp(dev_name(&pdev->dev), "nfit_test.0") == 0) {
+               rc = nfit_ctl_test(&pdev->dev);
+               if (rc)
+                       return rc;
+       }
+
        nfit_test = to_nfit_test(&pdev->dev);
 
        /* common alloc */
@@ -1639,11 +1865,13 @@ static __init int nfit_test_init(void)
 {
        int rc, i;
 
-       nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm");
-       if (IS_ERR(nfit_test_dimm))
-               return PTR_ERR(nfit_test_dimm);
+       nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm);
 
-       nfit_test_setup(nfit_test_lookup);
+       nfit_test_dimm = class_create(THIS_MODULE, "nfit_test_dimm");
+       if (IS_ERR(nfit_test_dimm)) {
+               rc = PTR_ERR(nfit_test_dimm);
+               goto err_register;
+       }
 
        for (i = 0; i < NUM_NFITS; i++) {
                struct nfit_test *nfit_test;
index c281dd2e5e2d8e631a2424a613841c7a40ab6601..f54c0032c6ff3a34e14504aa8fa5f219148267a3 100644 (file)
@@ -31,11 +31,17 @@ struct nfit_test_resource {
        void *buf;
 };
 
+union acpi_object;
+typedef void *acpi_handle;
+
 typedef struct nfit_test_resource *(*nfit_test_lookup_fn)(resource_size_t);
+typedef union acpi_object *(*nfit_test_evaluate_dsm_fn)(acpi_handle handle,
+               const u8 *uuid, u64 rev, u64 func, union acpi_object *argv4);
 void __iomem *__wrap_ioremap_nocache(resource_size_t offset,
                unsigned long size);
 void __wrap_iounmap(volatile void __iomem *addr);
-void nfit_test_setup(nfit_test_lookup_fn lookup);
+void nfit_test_setup(nfit_test_lookup_fn lookup,
+               nfit_test_evaluate_dsm_fn evaluate);
 void nfit_test_teardown(void);
 struct nfit_test_resource *get_nfit_res(resource_size_t resource);
 #endif
index 877a8a4721b679ea41c36464bc3bddcec44b9d53..c012edbdb13b65c5e8578242e996d1bc11dbcb33 100644 (file)
@@ -3,8 +3,8 @@ all:
 all: ring virtio_ring_0_9 virtio_ring_poll virtio_ring_inorder ptr_ring noring
 
 CFLAGS += -Wall
-CFLAGS += -pthread -O2 -ggdb
-LDFLAGS += -pthread -O2 -ggdb
+CFLAGS += -pthread -O2 -ggdb -flto -fwhole-program
+LDFLAGS += -pthread -O2 -ggdb -flto -fwhole-program
 
 main.o: main.c main.h
 ring.o: ring.c main.h
index 147abb452a6ccc098bf50338e0c353f4b8896f8a..f31353fac5415d8b9f5614e6f46f71a8f062f09b 100644 (file)
@@ -96,7 +96,13 @@ void set_affinity(const char *arg)
        assert(!ret);
 }
 
-static void run_guest(void)
+void poll_used(void)
+{
+       while (used_empty())
+               busy_wait();
+}
+
+static void __attribute__((__flatten__)) run_guest(void)
 {
        int completed_before;
        int completed = 0;
@@ -141,7 +147,7 @@ static void run_guest(void)
                assert(completed <= bufs);
                assert(started <= bufs);
                if (do_sleep) {
-                       if (enable_call())
+                       if (used_empty() && enable_call())
                                wait_for_call();
                } else {
                        poll_used();
@@ -149,7 +155,13 @@ static void run_guest(void)
        }
 }
 
-static void run_host(void)
+void poll_avail(void)
+{
+       while (avail_empty())
+               busy_wait();
+}
+
+static void __attribute__((__flatten__)) run_host(void)
 {
        int completed_before;
        int completed = 0;
@@ -160,7 +172,7 @@ static void run_host(void)
 
        for (;;) {
                if (do_sleep) {
-                       if (enable_kick())
+                       if (avail_empty() && enable_kick())
                                wait_for_kick();
                } else {
                        poll_avail();
index 16917acb0adef30beab588329e3e8e547aff04ef..34e63cc4c572bfcafe6fecb4784fc4ba5079bf8a 100644 (file)
@@ -56,15 +56,15 @@ void alloc_ring(void);
 int add_inbuf(unsigned, void *, void *);
 void *get_buf(unsigned *, void **);
 void disable_call();
+bool used_empty();
 bool enable_call();
 void kick_available();
-void poll_used();
 /* host side */
 void disable_kick();
+bool avail_empty();
 bool enable_kick();
 bool use_buf(unsigned *, void **);
 void call_used();
-void poll_avail();
 
 /* implemented by main */
 extern bool do_sleep;
index eda2f4824130e36f3970794f1a4b396809e6de44..b8d1c1daac7cc089734c6a6cf3453ae7277abe62 100644 (file)
@@ -24,8 +24,9 @@ void *get_buf(unsigned *lenp, void **bufp)
        return "Buffer";
 }
 
-void poll_used(void)
+bool used_empty()
 {
+       return false;
 }
 
 void disable_call()
@@ -54,8 +55,9 @@ bool enable_kick()
        assert(0);
 }
 
-void poll_avail(void)
+bool avail_empty()
 {
+       return false;
 }
 
 bool use_buf(unsigned *lenp, void **bufp)
index bd2ad1d3b7a9ef88e28e1ad982dd37638841fa04..635b07b4fdd3949c7883a2775575c0ff4d8ce228 100644 (file)
@@ -133,18 +133,9 @@ void *get_buf(unsigned *lenp, void **bufp)
        return datap;
 }
 
-void poll_used(void)
+bool used_empty()
 {
-       void *b;
-
-       do {
-               if (tailcnt == headcnt || __ptr_ring_full(&array)) {
-                       b = NULL;
-                       barrier();
-               } else {
-                       b = "Buffer\n";
-               }
-       } while (!b);
+       return (tailcnt == headcnt || __ptr_ring_full(&array));
 }
 
 void disable_call()
@@ -173,14 +164,9 @@ bool enable_kick()
        assert(0);
 }
 
-void poll_avail(void)
+bool avail_empty()
 {
-       void *b;
-
-       do {
-               barrier();
-               b = __ptr_ring_peek(&array);
-       } while (!b);
+       return !__ptr_ring_peek(&array);
 }
 
 bool use_buf(unsigned *lenp, void **bufp)
index c25c8d248b6b7dfc5a6e5bbce1bb9f6ba7561244..747c5dd47be8b075c7ca1558393e45c5b7a47e63 100644 (file)
@@ -163,12 +163,11 @@ void *get_buf(unsigned *lenp, void **bufp)
        return datap;
 }
 
-void poll_used(void)
+bool used_empty()
 {
        unsigned head = (ring_size - 1) & guest.last_used_idx;
 
-       while (ring[head].flags & DESC_HW)
-               busy_wait();
+       return (ring[head].flags & DESC_HW);
 }
 
 void disable_call()
@@ -180,13 +179,11 @@ void disable_call()
 
 bool enable_call()
 {
-       unsigned head = (ring_size - 1) & guest.last_used_idx;
-
        event->call_index = guest.last_used_idx;
        /* Flush call index write */
        /* Barrier D (for pairing) */
        smp_mb();
-       return ring[head].flags & DESC_HW;
+       return used_empty();
 }
 
 void kick_available(void)
@@ -213,20 +210,17 @@ void disable_kick()
 
 bool enable_kick()
 {
-       unsigned head = (ring_size - 1) & host.used_idx;
-
        event->kick_index = host.used_idx;
        /* Barrier C (for pairing) */
        smp_mb();
-       return !(ring[head].flags & DESC_HW);
+       return avail_empty();
 }
 
-void poll_avail(void)
+bool avail_empty()
 {
        unsigned head = (ring_size - 1) & host.used_idx;
 
-       while (!(ring[head].flags & DESC_HW))
-               busy_wait();
+       return !(ring[head].flags & DESC_HW);
 }
 
 bool use_buf(unsigned *lenp, void **bufp)
index 761866212aacf1149d03ef1151ac7727c944db72..bbc3043b2fb169aa4764922a786e9cbfc34761ed 100644 (file)
@@ -194,24 +194,16 @@ void *get_buf(unsigned *lenp, void **bufp)
        return datap;
 }
 
-void poll_used(void)
+bool used_empty()
 {
+       unsigned short last_used_idx = guest.last_used_idx;
 #ifdef RING_POLL
-       unsigned head = (ring_size - 1) & guest.last_used_idx;
+       unsigned short head = last_used_idx & (ring_size - 1);
+       unsigned index = ring.used->ring[head].id;
 
-       for (;;) {
-               unsigned index = ring.used->ring[head].id;
-
-               if ((index ^ guest.last_used_idx ^ 0x8000) & ~(ring_size - 1))
-                       busy_wait();
-               else
-                       break;
-       }
+       return (index ^ last_used_idx ^ 0x8000) & ~(ring_size - 1);
 #else
-       unsigned head = guest.last_used_idx;
-
-       while (ring.used->idx == head)
-               busy_wait();
+       return ring.used->idx == last_used_idx;
 #endif
 }
 
@@ -224,22 +216,11 @@ void disable_call()
 
 bool enable_call()
 {
-       unsigned short last_used_idx;
-
-       vring_used_event(&ring) = (last_used_idx = guest.last_used_idx);
+       vring_used_event(&ring) = guest.last_used_idx;
        /* Flush call index write */
        /* Barrier D (for pairing) */
        smp_mb();
-#ifdef RING_POLL
-       {
-               unsigned short head = last_used_idx & (ring_size - 1);
-               unsigned index = ring.used->ring[head].id;
-
-               return (index ^ last_used_idx ^ 0x8000) & ~(ring_size - 1);
-       }
-#else
-       return ring.used->idx == last_used_idx;
-#endif
+       return used_empty();
 }
 
 void kick_available(void)
@@ -266,36 +247,21 @@ void disable_kick()
 
 bool enable_kick()
 {
-       unsigned head = host.used_idx;
-
-       vring_avail_event(&ring) = head;
+       vring_avail_event(&ring) = host.used_idx;
        /* Barrier C (for pairing) */
        smp_mb();
-#ifdef RING_POLL
-       {
-               unsigned index = ring.avail->ring[head & (ring_size - 1)];
-
-               return (index ^ head ^ 0x8000) & ~(ring_size - 1);
-       }
-#else
-       return head == ring.avail->idx;
-#endif
+       return avail_empty();
 }
 
-void poll_avail(void)
+bool avail_empty()
 {
        unsigned head = host.used_idx;
 #ifdef RING_POLL
-       for (;;) {
-               unsigned index = ring.avail->ring[head & (ring_size - 1)];
-               if ((index ^ head ^ 0x8000) & ~(ring_size - 1))
-                       busy_wait();
-               else
-                       break;
-       }
+       unsigned index = ring.avail->ring[head & (ring_size - 1)];
+
+       return ((index ^ head ^ 0x8000) & ~(ring_size - 1));
 #else
-       while (ring.avail->idx == head)
-               busy_wait();
+       return head == ring.avail->idx;
 #endif
 }
 
index 6e9c40eea208a2e2e2f7e36e45dc7fc3329f5169..69ccce308458a4c3de79ab1b6ffceee0f2cfb47d 100644 (file)
@@ -305,7 +305,7 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
                        continue;
                type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
                       & ARMV8_PMU_EVTYPE_EVENT;
-               if ((type == ARMV8_PMU_EVTYPE_EVENT_SW_INCR)
+               if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
                    && (enable & BIT(i))) {
                        reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
                        reg = lower_32_bits(reg);
@@ -379,7 +379,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
        eventsel = data & ARMV8_PMU_EVTYPE_EVENT;
 
        /* Software increment event does't need to be backed by a perf event */
-       if (eventsel == ARMV8_PMU_EVTYPE_EVENT_SW_INCR)
+       if (eventsel == ARMV8_PMUV3_PERFCTR_SW_INCR &&
+           select_idx != ARMV8_PMU_CYCLE_IDX)
                return;
 
        memset(&attr, 0, sizeof(struct perf_event_attr));
@@ -391,7 +392,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
        attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
        attr.exclude_hv = 1; /* Don't count EL2 events */
        attr.exclude_host = 1; /* Don't count host events */
-       attr.config = eventsel;
+       attr.config = (select_idx == ARMV8_PMU_CYCLE_IDX) ?
+               ARMV8_PMUV3_PERFCTR_CPU_CYCLES : eventsel;
 
        counter = kvm_pmu_get_counter_value(vcpu, select_idx);
        /* The initial sample period (overflow count) of an event. */
index e18b30ddcdce94ae9577119f7bb7e1362adb25f5..ebe1b9fa3c4d39bdc04076d117a5d88970995c91 100644 (file)
@@ -453,17 +453,33 @@ struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev)
        return container_of(dev, struct vgic_io_device, dev);
 }
 
-static bool check_region(const struct vgic_register_region *region,
+static bool check_region(const struct kvm *kvm,
+                        const struct vgic_register_region *region,
                         gpa_t addr, int len)
 {
-       if ((region->access_flags & VGIC_ACCESS_8bit) && len == 1)
-               return true;
-       if ((region->access_flags & VGIC_ACCESS_32bit) &&
-           len == sizeof(u32) && !(addr & 3))
-               return true;
-       if ((region->access_flags & VGIC_ACCESS_64bit) &&
-           len == sizeof(u64) && !(addr & 7))
-               return true;
+       int flags, nr_irqs = kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+
+       switch (len) {
+       case sizeof(u8):
+               flags = VGIC_ACCESS_8bit;
+               break;
+       case sizeof(u32):
+               flags = VGIC_ACCESS_32bit;
+               break;
+       case sizeof(u64):
+               flags = VGIC_ACCESS_64bit;
+               break;
+       default:
+               return false;
+       }
+
+       if ((region->access_flags & flags) && IS_ALIGNED(addr, len)) {
+               if (!region->bits_per_irq)
+                       return true;
+
+               /* Do we access a non-allocated IRQ? */
+               return VGIC_ADDR_TO_INTID(addr, region->bits_per_irq) < nr_irqs;
+       }
 
        return false;
 }
@@ -477,7 +493,7 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 
        region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
                                       addr - iodev->base_addr);
-       if (!region || !check_region(region, addr, len)) {
+       if (!region || !check_region(vcpu->kvm, region, addr, len)) {
                memset(val, 0, len);
                return 0;
        }
@@ -510,10 +526,7 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 
        region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
                                       addr - iodev->base_addr);
-       if (!region)
-               return 0;
-
-       if (!check_region(region, addr, len))
+       if (!region || !check_region(vcpu->kvm, region, addr, len))
                return 0;
 
        switch (iodev->iodev_type) {
index 4c34d39d44a0eabe1a8b70d16380d0cf8ae1787a..84961b4e4422fcf50800e156063a1595969851cd 100644 (file)
@@ -50,15 +50,15 @@ extern struct kvm_io_device_ops kvm_io_gic_ops;
 #define VGIC_ADDR_IRQ_MASK(bits) (((bits) * 1024 / 8) - 1)
 
 /*
- * (addr & mask) gives us the byte offset for the INT ID, so we want to
- * divide this with 'bytes per irq' to get the INT ID, which is given
- * by '(bits) / 8'.  But we do this with fixed-point-arithmetic and
- * take advantage of the fact that division by a fraction equals
- * multiplication with the inverted fraction, and scale up both the
- * numerator and denominator with 8 to support at most 64 bits per IRQ:
+ * (addr & mask) gives us the _byte_ offset for the INT ID.
+ * We multiply this by 8 the get the _bit_ offset, then divide this by
+ * the number of bits to learn the actual INT ID.
+ * But instead of a division (which requires a "long long div" implementation),
+ * we shift by the binary logarithm of <bits>.
+ * This assumes that <bits> is a power of two.
  */
 #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
-                                       64 / (bits) / 8)
+                                       8 >> ilog2(bits))
 
 /*
  * Some VGIC registers store per-IRQ information, with a different number
index 0a063af4056546c886d6d7efba987ff5528fcce0..9bab86757fa4f3613c372fbc0250c146284306ff 100644 (file)
@@ -50,8 +50,10 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
 
                        WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
 
-                       kvm_notify_acked_irq(vcpu->kvm, 0,
-                                            intid - VGIC_NR_PRIVATE_IRQS);
+                       /* Only SPIs require notification */
+                       if (vgic_valid_spi(vcpu->kvm, intid))
+                               kvm_notify_acked_irq(vcpu->kvm, 0,
+                                                    intid - VGIC_NR_PRIVATE_IRQS);
                }
        }
 
index 9f0dae397d9c818b1d0237076d0bc59020a05950..5c9f9745e6cab8284161397c3d810df65304fae8 100644 (file)
@@ -41,8 +41,10 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 
                        WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
 
-                       kvm_notify_acked_irq(vcpu->kvm, 0,
-                                            intid - VGIC_NR_PRIVATE_IRQS);
+                       /* Only SPIs require notification */
+                       if (vgic_valid_spi(vcpu->kvm, intid))
+                               kvm_notify_acked_irq(vcpu->kvm, 0,
+                                                    intid - VGIC_NR_PRIVATE_IRQS);
                }
 
                /*
index 2893d5ba523ad26f139fbac8d2dd1c2aa43649ad..6440b56ec90e2198a234fa9b09d87b0c518efea7 100644 (file)
@@ -273,6 +273,18 @@ retry:
                 * no more work for us to do.
                 */
                spin_unlock(&irq->irq_lock);
+
+               /*
+                * We have to kick the VCPU here, because we could be
+                * queueing an edge-triggered interrupt for which we
+                * get no EOI maintenance interrupt. In that case,
+                * while the IRQ is already on the VCPU's AP list, the
+                * VCPU could have EOI'ed the original interrupt and
+                * won't see this one until it exits for some other
+                * reason.
+                */
+               if (vcpu)
+                       kvm_vcpu_kick(vcpu);
                return false;
        }
 
index db9668869f6ff6866a72f278def5770d71190994..efeceb0a222dd8a793cd8d7e5a7770b7799851c3 100644 (file)
@@ -84,12 +84,14 @@ static void async_pf_execute(struct work_struct *work)
         * mm and might be done in another context, so we must
         * use FOLL_REMOTE.
         */
-       __get_user_pages_unlocked(NULL, mm, addr, 1, 1, 0, NULL, FOLL_REMOTE);
+       __get_user_pages_unlocked(NULL, mm, addr, 1, NULL,
+                       FOLL_WRITE | FOLL_REMOTE);
 
        kvm_async_page_present_sync(vcpu, apf);
 
        spin_lock(&vcpu->async_pf.lock);
        list_add_tail(&apf->link, &vcpu->async_pf.done);
+       apf->vcpu = NULL;
        spin_unlock(&vcpu->async_pf.lock);
 
        /*
@@ -112,6 +114,8 @@ static void async_pf_execute(struct work_struct *work)
 
 void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
 {
+       spin_lock(&vcpu->async_pf.lock);
+
        /* cancel outstanding work queue item */
        while (!list_empty(&vcpu->async_pf.queue)) {
                struct kvm_async_pf *work =
@@ -119,6 +123,14 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
                                         typeof(*work), queue);
                list_del(&work->queue);
 
+               /*
+                * We know it's present in vcpu->async_pf.done, do
+                * nothing here.
+                */
+               if (!work->vcpu)
+                       continue;
+
+               spin_unlock(&vcpu->async_pf.lock);
 #ifdef CONFIG_KVM_ASYNC_PF_SYNC
                flush_work(&work->work);
 #else
@@ -128,9 +140,9 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
                        kmem_cache_free(async_pf_cache, work);
                }
 #endif
+               spin_lock(&vcpu->async_pf.lock);
        }
 
-       spin_lock(&vcpu->async_pf.lock);
        while (!list_empty(&vcpu->async_pf.done)) {
                struct kvm_async_pf *work =
                        list_first_entry(&vcpu->async_pf.done,
index f397e9b20370a2fb547b04fe555802846b2e9aef..a29786dd95221017b141a060b031c5c899dac2e5 100644 (file)
@@ -42,6 +42,7 @@
 
 #ifdef CONFIG_HAVE_KVM_IRQFD
 
+static struct workqueue_struct *irqfd_cleanup_wq;
 
 static void
 irqfd_inject(struct work_struct *work)
@@ -167,7 +168,7 @@ irqfd_deactivate(struct kvm_kernel_irqfd *irqfd)
 
        list_del_init(&irqfd->list);
 
-       schedule_work(&irqfd->shutdown);
+       queue_work(irqfd_cleanup_wq, &irqfd->shutdown);
 }
 
 int __attribute__((weak)) kvm_arch_set_irq_inatomic(
@@ -554,7 +555,7 @@ kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args)
         * so that we guarantee there will not be any more interrupts on this
         * gsi once this deassign function returns.
         */
-       flush_work(&irqfd->shutdown);
+       flush_workqueue(irqfd_cleanup_wq);
 
        return 0;
 }
@@ -591,7 +592,7 @@ kvm_irqfd_release(struct kvm *kvm)
         * Block until we know all outstanding shutdown jobs have completed
         * since we do not take a kvm* reference.
         */
-       flush_work(&irqfd->shutdown);
+       flush_workqueue(irqfd_cleanup_wq);
 
 }
 
@@ -621,8 +622,23 @@ void kvm_irq_routing_update(struct kvm *kvm)
        spin_unlock_irq(&kvm->irqfds.lock);
 }
 
+/*
+ * create a host-wide workqueue for issuing deferred shutdown requests
+ * aggregated from all vm* instances. We need our own isolated
+ * queue to ease flushing work items when a VM exits.
+ */
+int kvm_irqfd_init(void)
+{
+       irqfd_cleanup_wq = alloc_workqueue("kvm-irqfd-cleanup", 0, 0);
+       if (!irqfd_cleanup_wq)
+               return -ENOMEM;
+
+       return 0;
+}
+
 void kvm_irqfd_exit(void)
 {
+       destroy_workqueue(irqfd_cleanup_wq);
 }
 #endif
 
index 81dfc73d3df39851e3b44cd546f5f66046ec5e0f..7f9ee2929cfea3ba0d30740e5c82109c14d359e4 100644 (file)
@@ -1346,21 +1346,19 @@ unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *w
 static int get_user_page_nowait(unsigned long start, int write,
                struct page **page)
 {
-       int flags = FOLL_TOUCH | FOLL_NOWAIT | FOLL_HWPOISON | FOLL_GET;
+       int flags = FOLL_NOWAIT | FOLL_HWPOISON;
 
        if (write)
                flags |= FOLL_WRITE;
 
-       return __get_user_pages(current, current->mm, start, 1, flags, page,
-                       NULL, NULL);
+       return get_user_pages(start, 1, flags, page, NULL);
 }
 
 static inline int check_user_page_hwpoison(unsigned long addr)
 {
-       int rc, flags = FOLL_TOUCH | FOLL_HWPOISON | FOLL_WRITE;
+       int rc, flags = FOLL_HWPOISON | FOLL_WRITE;
 
-       rc = __get_user_pages(current, current->mm, addr, 1,
-                             flags, NULL, NULL, NULL);
+       rc = get_user_pages(addr, 1, flags, NULL, NULL);
        return rc == -EHWPOISON;
 }
 
@@ -1416,10 +1414,15 @@ static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault,
                down_read(&current->mm->mmap_sem);
                npages = get_user_page_nowait(addr, write_fault, page);
                up_read(&current->mm->mmap_sem);
-       } else
+       } else {
+               unsigned int flags = FOLL_TOUCH | FOLL_HWPOISON;
+
+               if (write_fault)
+                       flags |= FOLL_WRITE;
+
                npages = __get_user_pages_unlocked(current, current->mm, addr, 1,
-                                                  write_fault, 0, page,
-                                                  FOLL_TOUCH|FOLL_HWPOISON);
+                                                  page, flags);
+       }
        if (npages != 1)
                return npages;
 
@@ -2886,10 +2889,10 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
 
        ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
        if (ret < 0) {
-               ops->destroy(dev);
                mutex_lock(&kvm->lock);
                list_del(&dev->vm_node);
                mutex_unlock(&kvm->lock);
+               ops->destroy(dev);
                return ret;
        }
 
@@ -3841,7 +3844,12 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
         * kvm_arch_init makes sure there's at most one caller
         * for architectures that support multiple implementations,
         * like intel and amd on x86.
+        * kvm_arch_init must be called before kvm_irqfd_init to avoid creating
+        * conflicts in case kvm is already setup for another implementation.
         */
+       r = kvm_irqfd_init();
+       if (r)
+               goto out_irqfd;
 
        if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {
                r = -ENOMEM;
@@ -3923,6 +3931,7 @@ out_free_0a:
        free_cpumask_var(cpus_hardware_enabled);
 out_free_0:
        kvm_irqfd_exit();
+out_irqfd:
        kvm_arch_exit();
 out_fail:
        return r;